Java官方笔记4类和对象

news/2024/11/26 1:59:40/

创建类

定义类Bicycle:

public class Bicycle {// the Bicycle class has// three fieldspublic int cadence;public int gear;public int speed;// the Bicycle class has// one constructorpublic Bicycle(int startCadence, int startSpeed, int startGear) {gear = startGear;cadence = startCadence;speed = startSpeed;}// the Bicycle class has// four methodspublic void setCadence(int newValue) {cadence = newValue;}public void setGear(int newValue) {gear = newValue;}public void applyBrake(int decrement) {speed -= decrement;}public void speedUp(int increment) {speed += increment;}
}

创建子类MountainBike继承类Bicycle:

public class MountainBike extends Bicycle {// the MountainBike subclass has// one fieldpublic int seatHeight;// the MountainBike subclass has// one constructorpublic MountainBike(int startHeight, int startCadence,int startSpeed, int startGear) {super(startCadence, startSpeed, startGear);seatHeight = startHeight;}   // the MountainBike subclass has// one methodpublic void setHeight(int newValue) {seatHeight = newValue;}   
}

可以看出定义类的语法如下:

class MyClass {// field, constructor, and // method declarations
}

复杂点的:

class MyClass extends MySuperClass implements YourInterface {// field, constructor, and// method declarations
}

定义了类MyClass继承类MySuperClass,并实现接口YourInterface。类只能有一个父类,但是能实现多个接口。

定义方法

方法定义示例:

public double calculateAnswer(double wingSpan, int numberOfEngines,double length, double grossTons) {//do the calculation here
}

方法签名,方法名+参数类型,比如上面的方法签名是:

calculateAnswer(double, int, double, double)

1个类中可以有多个同名的,但是不同参数的方法,也就是方法重载:

public class DataArtist {...public void draw(String s) {...}public void draw(int i) {...}public void draw(double f) {...}public void draw(int i, double f) {...}
}

但是方法重载应谨慎使用,它会降低代码可读性。

类构造器

类有个默认的无参数的构造器,也可以自定义:

public Bicycle(int startCadence, int startSpeed, int startGear) {gear = startGear;cadence = startCadence;speed = startSpeed;
}

构造器跟类同名,没有return。类可以有多个不同参数列表的构造器。

调用

参数定义的叫做Parameters ,实际传入的叫做Arguments

基本数据类型

public double computePayment(double loanAmt,double rate,double futureValue,int numPeriods) {double interest = rate / 100.0;double partial1 = Math.pow((1 + interest), - numPeriods);double denominator = (1 - partial1) / interest;double answer = (-loanAmt / denominator)- ((futureValue * partial1) / denominator);return answer;
}

类对象

public Polygon polygonFrom(Point[] corners) {// method body goes here
}

可变参数

public Polygon polygonFrom(Point... corners) {int numberOfSides = corners.length;double squareOfSide1, lengthOfSide1;squareOfSide1 = (corners[1].x - corners[0].x)* (corners[1].x - corners[0].x) + (corners[1].y - corners[0].y)* (corners[1].y - corners[0].y);lengthOfSide1 = Math.sqrt(squareOfSide1);// more method body code follows that creates and returns a // polygon connecting the Points
}

使用...来表示可变参数。

方法中的基本数据类型,return后消失:

public class PassPrimitiveByValue {public static void main(String[] args) {int x = 3;// invoke passMethod() with // x as argumentpassMethod(x);// print x to see if its // value has changedSystem.out.println("After invoking passMethod, x = " + x);}// change parameter in passMethod()public static void passMethod(int p) {p = 10;}
}

方法中的引用类型,return后还有作用到原来的对象:

public class RefType {public void moveCircle(Circle circle, int deltaX, int deltaY) {// code to move origin of circle to x+deltaX, y+deltaYcircle.setX(circle.getX() + deltaX);circle.setY(circle.getY() + deltaY);// code to assign a new reference to circlecircle = new Circle(0, 0);}public static void main(String[] args) {Circle circle = new Circle(1, 1);RefType refType = new RefType();refType.moveCircle(circle, 2, 2);System.out.println(circle.getX());}
}

运行结果为3。moveCircle里面的circle,set方法调用会影响到引用的对象。虽然最后new了一个新对象,但是赋值给的是方法内部的这个circle,return后消失,外面的circle不受影响。可以这么理解,外面和里面的两个circle,引用的都是同一个对象。

对象

创建对象:

Point originOne = new Point(23, 94);
Rectangle rectOne = new Rectangle(originOne, 100, 200);
Rectangle rectTwo = new Rectangle(50, 100);

变量声明:

type name;

如果是基本数据类型,则会先分配内存空间。如果是类引用,则不会,在new的时候才会分配内存空间。

字段:

objectReference.fieldName

方法:

objectReference.methodName(argumentList);

请记住,一个对象能有多个引用。

类的高级用法

方法退出有3种情况:

  1. 代码执行完

  2. throw异常

  3. return

返回类型如果是类,那么可以return子类。返回类型如果是接口,那么可以return接口实现类。

this关键字表示当前类,或用来调用其他构造方法:

public class Rectangle {private int x, y;private int width, height;public Rectangle() {this(0, 0, 1, 1);}public Rectangle(int width, int height) {this(0, 0, width, height);}public Rectangle(int x, int y, int width, int height) {this.x = x;this.y = y;this.width = width;this.height = height;}...
}

调用其他构造方法必须放在第一行。

范围控制

top级别:public、package-private

member级别:public、private、protected、package-private

其中注意protected,等于package-private + 其他包中的子类(继承了当前类,但是在其他包里面)

怎么理解?在自己的地盘(package)随便玩,但是到了其他地盘,必须有父类保护(protected)

第3列的Subclass指的是其他包的子类。

访问控制有2个用途:

  1. 在用别人的类时,看哪些可以使用

  2. 定义自己的类时,决定哪些允许别人用

static关键字,创建类字段:

public class Bicycle {private int cadence;private int gear;private int speed;private int id;private static int numberOfBicycles = 0;public Bicycle(int startCadence, int startSpeed, int startGear){gear = startGear;cadence = startCadence;speed = startSpeed;// increment number of Bicycles// and assign ID numberid = ++numberOfBicycles;}// new method to return the ID instance variablepublic int getID() {return id;}...
}

可以直接用类名访问:

Bicycle.numberOfBicycles

static关键字

创建类方法:

public static int getNumberOfBicycles() {return numberOfBicycles;
}

创建常量:

static final double PI = 3.141592653589793;

注意,基本数据类型或string的常量,会在编译的时候直接替换。如果依赖外部包的常量值变化了,比如PI变成了3.9,那么当前代码需要重新编译。

关于static,有一个很重要的点是:static只能访问static,也就是class级别只能访问class级别,如果想访问member级别,必须实例化对象后通过引用来访问。

static块

对于字段初始化来说,如果想写多行代码来初始化(比如写个for循环来填充复杂数组),instance级别可以在构造函数来做,而对于class级别呢?就可以使用static块:

public class MyClass {public static int x;public static int y;static {x = 10;y = 20;System.out.println("静态块执行");}public static void main(String[] args) {System.out.println("x=" + x);System.out.println("y=" + y);}
}

static块是用来给class级别字段做值初始化的,它们会按照在类中出现的顺序依次执行,并且它们在构造函数之前执行。

也可以定义static方法后赋值:

class Whatever {public static varType myVar = initializeClassVariable();private static varType initializeClassVariable() {// initialization code goes here}
}

member级别字段初始化块,也就是不带static的:

{// whatever code is needed for initialization goes here
}

会在每个constructor中执行。也可以使用final方法:

class Whatever {private varType myVar = initializeInstanceVariable();protected final varType initializeInstanceVariable() {// initialization code goes here}
}

为什么这里必须要用final?因为在实例初始化期间调用非final方法会报错,这是为了提高代码健壮性、可读性和可维护性,初始化本来就是一个确定的事情,那么就用final限定清楚。

嵌套类

class OuterClass {...class InnerClass {...}static class StaticNestedClass {...}
}

InnerClass能访问OutClass所有成员(可以理解为跟method类似),StaticNestedClass则不能。

什么情况需要用嵌套类?

  • 这个类只会被另外1个类使用,那么可以定义为嵌套类(helper classes),优化包结构

  • 封装,嵌套类可以访问内部private成员

  • 可读性,小的嵌套类,方便阅读

必须先实例化OuterClass再实例化InnerClass:

OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();

而static嵌套类跟普通类一样:

StaticNestedClass staticNestedObject = new StaticNestedClass();

注意,static嵌套类,跟其他顶层类是一样的,意味着它不能直接访问所在类的字段,而必须通过实例化对象引用才能访问。(也许是为了方便在一个文件里面写多个类,才设计了static嵌套类)

以下是示例:

OuterClass.java

public class OuterClass {String outerField = "Outer field";static String staticOuterField = "Static outer field";class InnerClass {void accessMembers() {System.out.println(outerField);System.out.println(staticOuterField);}}static class StaticNestedClass {void accessMembers(OuterClass outer) {// Compiler error: Cannot make a static reference to the non-static//     field outerField// System.out.println(outerField);System.out.println(outer.outerField);System.out.println(staticOuterField);}}public static void main(String[] args) {System.out.println("Inner class:");System.out.println("------------");OuterClass outerObject = new OuterClass();OuterClass.InnerClass innerObject = outerObject.new InnerClass();innerObject.accessMembers();System.out.println("\nStatic nested class:");System.out.println("--------------------");StaticNestedClass staticNestedObject = new StaticNestedClass();staticNestedObject.accessMembers(outerObject);System.out.println("\nTop-level class:");System.out.println("--------------------");TopLevelClass topLevelObject = new TopLevelClass();topLevelObject.accessMembers(outerObject);}
}

TopLevelClass.java

public class TopLevelClass {void accessMembers(OuterClass outer) {// Compiler error: Cannot make a static reference to the non-static//     field OuterClass.outerField// System.out.println(OuterClass.outerField);System.out.println(outer.outerField);System.out.println(OuterClass.staticOuterField);}
}

一个变量引用的例子,这个例子展示了不同级别的同名变量,是如何取值的:

public class ShadowTest {public int x = 0;class FirstLevel {public int x = 1;void methodInFirstLevel(int x) {System.out.println("x = " + x);System.out.println("this.x = " + this.x);System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);}}public static void main(String... args) {ShadowTest st = new ShadowTest();ShadowTest.FirstLevel fl = st.new FirstLevel();fl.methodInFirstLevel(23);}
}
x = 23
this.x = 1
ShadowTest.this.x = 0  // 注意这种在嵌套类取OuterClass同名字段的方式

Local Class,定义在method里面的嵌套类:

public class LocalClassExample {static String regularExpression = "[^0-9]";public static void validatePhoneNumber(String phoneNumber1, String phoneNumber2) {final int numberLength = 10;// Valid in JDK 8 and later:// int numberLength = 10;class PhoneNumber {String formattedPhoneNumber = null;PhoneNumber(String phoneNumber){// numberLength = 7;String currentNumber = phoneNumber.replaceAll(regularExpression, "");if (currentNumber.length() == numberLength)formattedPhoneNumber = currentNumber;elseformattedPhoneNumber = null;}public String getNumber() {return formattedPhoneNumber;}// Valid in JDK 8 and later://            public void printOriginalNumbers() {
//                System.out.println("Original numbers are " + phoneNumber1 +
//                    " and " + phoneNumber2);
//            }}PhoneNumber myNumber1 = new PhoneNumber(phoneNumber1);PhoneNumber myNumber2 = new PhoneNumber(phoneNumber2);// Valid in JDK 8 and later://        myNumber1.printOriginalNumbers();if (myNumber1.getNumber() == null)System.out.println("First number is invalid");elseSystem.out.println("First number is " + myNumber1.getNumber());if (myNumber2.getNumber() == null)System.out.println("Second number is invalid");elseSystem.out.println("Second number is " + myNumber2.getNumber());}public static void main(String... args) {validatePhoneNumber("123-456-7890", "456-7890");}
}

Local Class只能访问方法里面的final变量,或者“看似final”的变量(值不会发生变化)。否则会报错:local variables referenced from an inner class must be final or effectively final。但是能直接方法参数列表的parameters。

Anonymous Class,定义在method里面的没有名字的嵌套类:

public class HelloWorldAnonymousClasses {interface HelloWorld {public void greet();public void greetSomeone(String someone);}public void sayHello() {class EnglishGreeting implements HelloWorld {String name = "world";public void greet() {greetSomeone("world");}public void greetSomeone(String someone) {name = someone;System.out.println("Hello " + name);}}HelloWorld englishGreeting = new EnglishGreeting();HelloWorld frenchGreeting = new HelloWorld() {  // 匿名类String name = "tout le monde";public void greet() {greetSomeone("tout le monde");}public void greetSomeone(String someone) {name = someone;System.out.println("Salut " + name);}};HelloWorld spanishGreeting = new HelloWorld() {  // 匿名类String name = "mundo";public void greet() {greetSomeone("mundo");}public void greetSomeone(String someone) {name = someone;System.out.println("Hola, " + name);}};englishGreeting.greet();frenchGreeting.greetSomeone("Fred");spanishGreeting.greet();}public static void main(String... args) {HelloWorldAnonymousClasses myApp =new HelloWorldAnonymousClasses();myApp.sayHello();}
}

它的语法跟constructor类似,new后面跟上implements接口或extends类的名字,但它是一个表达式,所以最后要加上分号。

请记住,Local Class和Anonymous Class,都是应以在method里面的。

参考资料:

Classes and Objects https://dev.java/learn/classes-objects/


http://www.ppmy.cn/news/185452.html

相关文章

富士施乐Fuji Xerox WorkCentre 3325 驱动

富士施乐Fuji Xerox WorkCentre 3325 驱动是官方提供的一款一体机(打印、扫描)驱动,本站收集提供高速下载,用于解决一体机与电脑连接不了,无法正常使用的问题,本动适用于:Windows XP / Windows 7 / Windows 8 / Window…

富士相机设置传原图_【富士 X-E3 无反相机使用体验】蓝牙|WIFI|连接|图像传输_摘要频道_什么值得买...

富士 X-E3 无反相机使用体验(蓝牙|WIFI|连接|图像传输) 一,蓝牙和WIFI 特别说明:蓝牙和wifi连接的稳定性,和手机有很大的关系,我使用的是锤子坚果Pro手机,官方应用市场里没有富士的Camera Remote软件,和软件…

ubuntu fuji xerox scanner扫描仪安装和使用

打印功能可以直接添加,但是扫描功能不方便使用,无法简单使用: sudo sane-find-scannerscanimage -L 这两步完成配置(未成功)。 需要配置驱动,适用于18.04和20.04。 安装 对应于64位系统,使…

科技新品 | 军规级户外运动智能手表;本田赛车合作款金属计时表;富士影像数字印刷设备...

“科技新产品动态”栏目把新鲜的具有代表性的科学产品带到您眼前,涉及消费电子,半导体、服务器、智能家电等众多品类,提供图片和简单的文字介绍。 智能穿戴设备品牌Amazfit发布最新版户外运动智能手表系列;卡西欧与本田赛车联合推…

Ios面试题

http://lqcjdx.blog.163.com/blog/static/207489241201392282737189/ 看到这个关键字,我们就应该想到,这是Object-C对C语言的扩展,例如interface XXX。 interface 声明类 implementation 实现类 protocol 声明协议 optio…

DICOM世界观·第二章 数字(D)、成像(I)与通讯(Co)

背景: 正如同笛卡尔定义了我们所生活在的三维世界和爱因斯坦定义了第四维度时间,在第一章中我们给出了统一的标定DICOM世界的坐标系,以及相关的变换理论,接下来我们要逐步走进DICOM世界内部,观察其内部的“真实景象”…

富士长焦机使用技巧

1、点测光怎么用? 点测光是从P档开始的手动档才有的测光方式,从AUTO开始的自动档没有。首先转到这些档,按相机最中间的那个功能键,出现调节菜单,然后用上下键调到测光处,再用左右键调到中间只有一个点的测光…

[MoocPython课程]Turtlr库绘图之“富士山下”

找到一个挺漂亮的图片,我们试着用python把它画出来。 打算的构图: 1.富士山 2.花田 3.樱花树 4.樱花雨 第一步,导入绘图库,建立画布,找准坐标,做到心中有数 import turtle as t t.setup(800,600,0,0)画布中…