Java基础知识4_Java核心类2

 

JavaBean

有的class定义符合这样的形式:
若干private实例字段;
通过public方法来读写这些实例字段。

如果读写方法符合以下这种命名规范:
// 读方法:
public Type getXyz()
// 写方法:
public void setXyz(Type value)

那么这种class被称为JavaBean

如果字段名是xyz,那么读写方法名分别以get和set开头,并且后接大写字母开头的字段名Xyz,因此两个读写方法名分别是getXyz()和setXyz()。

oolean字段比较特殊,它的读方法一般命名为is...():

// 读方法:
public boolean isChild()
// 写方法:
public void setChild(boolean value)

一组对应的读方法(getter)和写方法(setter)称为属性(property)

例如,name属性:
对应的读方法是String getName()
对应的写方法是setName(String)

只有getter的属性称为只读属性(read-only),例如,定义一个age只读属性:
只有对应的读方法是int getAge(),无对应的写方法setAge(int)。
类似的,只有setter的属性称为只写属性(write-only)。

属性只需要定义getter和setter方法(或is方法),不一定要有对应的字段。

可以看出,getter和setter也是一种数据封装的方法。

JavaBean的作用
JavaBean主要用来传递数据,即把一组数据组合成一个JavaBean便于传输。
此外,JavaBean可以方便地被IDE工具分析,生成读写属性的代码,主要用在图形界面的可视化设计中。
通过IDE,可以快速生成getter和setter。例如,在Eclipse中,先输入以下代码:
public class Person {
private String name;
private int age;
}
然后,点击右键,在弹出的菜单中选择“Source”,“Generate Getters and Setters”,在弹出的对话框中选中需要生成getter和setter方法的字段,点击确定即可由IDE自动完成所有方法代码。

要枚举一个JavaBean的所有属性,可以直接使用Java核心库提供的Introspector:

public class Main {
public static void main(String[] args) throws Exception {
BeanInfo info = Introspector.getBeanInfo(Person.class);
for (PropertyDescriptor pd : info.getPropertyDescriptors()) {
System.out.println(pd.getName());
System.out.println(" " + pd.getReadMethod());
System.out.println(" " + pd.getWriteMethod());
}
}
}

class Person {
private String name;
private int age;

......
}

运行上述代码,可以列出所有的属性,以及对应的读写方法。
注意class属性是从Object继承的getClass()方法带来的。

小结
JavaBean是一种符合命名规范的class,它通过getter和setter来定义属性;

属性是一种通用的叫法,并非Java语法规定;

可以利用IDE快速生成getter和setter;

使用Introspector.getBeanInfo()可以获取属性列表。


枚举类enum
为了让编译器能自动检查某个值在枚举的集合内,并且,不同用途的枚举需要不同的类型来标记,不能混用,我们可以使用enum来定义枚举类:
enum Weekday {
SUN, MON, TUE, WED, THU, FRI, SAT;
}
使用:Weekday.SUN
使用enum定义枚举有如下好处:

首先,enum常量本身带有类型信息,即Weekday.SUN的类型是Weekday,同类型才能用==比较,编译器会自动检查出类型错误。

enum的比较
enum定义的枚举类是一种引用类型。
引用类型始终使用equals()方法,但enum类型可以例外,这是因为enum类型的每个常量在JVM中只有一个唯一实例。

enum类型
通过enum定义的枚举类,和其他的class有什么区别?

答案是没有任何区别。enum定义的类型就是class,只不过它有以下几个特点:

1.定义的enum类型总是继承自java.lang.Enum,且无法被继承;
2.只能直接定义enum的实例,而无法通过new操作符创建enum的实例;
3.定义的每个实例都是引用类型的唯一实例;
4.可以将enum类型用于switch语句。

因为enum是一个class,每个枚举的值都是class实例,因此,这些实例有一些方法:
name()
返回常量名,例如:
String s = Weekday.SUN.name(); // "SUN"

ordinal()
返回定义的常量的顺序,从0开始计数,例如:

int n = Weekday.MON.ordinal(); // 1(前提是MON是enum定义的第二项)

增加enum属性
因为enum本身是class,所以我们可以定义private的构造方法,并且,给每个枚举常量添加字段:

enum Weekday {
MON(1), TUE(2), WED(3), THU(4), FRI(5), SAT(6), SUN(0);

public final int dayValue;

private Weekday(int dayValue) {
this.dayValue = dayValue;
}
}
这样在初始化枚举变量的值时,可以将固定的数值赋值给dayValue,不用担心枚举变量的定义顺序发生变化。
Weekday day = Weekday.SUN; //执行语句后,dayValue通过构造函数获得值0;
enum的构造方法要声明为private,字段建议声明为final

toString()可以被覆写,而name()则不行。我们可以给Weekday添加toString()方法:
enum Weekday {
MON(1, "星期一"), TUE(2, "星期二"), WED(3, "星期三"), THU(4, "星期四"), FRI(5, "星期五"), SAT(6, "星期六"), SUN(0, "星期日");

public final int dayValue;
private final String chinese;

private Weekday(int dayValue, String chinese) {
this.dayValue = dayValue;
this.chinese = chinese;
}

@Override
public String toString() {
return this.chinese;
}
}
覆写toString()的目的是在输出时更有可读性。

最后,枚举类可以应用在switch语句中。因为枚举类天生具有类型信息和有限个枚举常量,所以比int、String类型更适合用在switch语句中:
switch(day) {
case MON:
case TUE:
case WED:
case THU:
case FRI:
System.out.println("Today is " + day + ". Work at office!");
break;
...

记录类record
从Java 14开始,引入了新的Record类。我们定义Record类时,使用关键字record。
public record Point(int x, int y) {}
把public record Point(int x, int y) {.....}类定义为record,相当于自动为Point类定义了
private final int x;
private final int y;
字段和
public int x() { return this.x; }
public int y() { return this.y; }
public String toString() {
return String.format("Point[x=%s, y=%s]", x, y);
}
public boolean equals(Object o) {
...
}
public int hashCode() {
...
}
...等方法
可以修改构造方法:
public Point {
if (x < 0 || y < 0) {
throw new IllegalArgumentException();
}
}

添加静态方法
作为record的Point仍然可以添加静态方法。一种常用的静态方法是of()方法,用来创建Point:

public record Point(int x, int y) {
public static Point of() {
return new Point(0, 0);
}
public static Point of(int x, int y) {
return new Point(x, y);
}
}
这样我们可以写出更简洁的代码:

var z = Point.of();
var p = Point.of(123, 456);



posted @ 2020-07-23 10:07  折纸_泛舟  阅读(160)  评论(0)    收藏  举报