【Core Java】05 Java 类的设计及特性

类的设计及特性

类的设计

隐藏数据

为了类的封装性,在设计类时,应该避免直接对外开发数据域。为了保证开发者不依赖于我们的底层细节,应该隐藏数据域(因为不能保证数据形式不会变化),并提供稳定的接口。

必要时,会提供访问器和更改器,对数据进行访问保护。

public long getAge() {
    
    
    return this.age;
}
public void setAge(int age) {
    
    
    // 校验 age 是否和发
    if(/* condition */){
    
    
        this.age = age;
    }
}

bool:

public boolean isMale() {
    
    
    return te;
}

public void setMale(boolean male) {
    
    
    this.amle = male;
}

引用类型:

返回一个引用就相当于直接暴露了数据,应该避免这么做,我们可以返回一个副本。

public String getName() {
    
    
    return this.name.clone();
}

不过,对于String则没有这个顾虑,因为String是不可变的。

工厂方法

当某个类足够复杂时,用工厂方法来构造实例可能是更好的解决方法。

例如,该类根据功能不同拥有多个子类,此时就可以用工厂方法,并以多态的形式返回新实例。

单元测试

任何类都可以拥有一个main方法,由于任何一个main方法都可以作为 Java 程序的入口,所以我们可以方便地进行单元测试。

例如我们要测试类 A,那么就应该在类 A 中实现一个main方法,然后java A运行测试。

可变参方法

像 C/C++ 中的printf函数那样,输入任意个参数。

在 Java 中,只需要使用下面这种语法:

void method(Object...args) {
    
    
    for(Object obj : args) {
    
    
        // ... obj
    }
}

从实现者的视角来看,Object...与一个Object[]的行为没有任何区别。

而从调用者的视角来看,则是可以传入任意个参数。

包装类

包装类是基本类型的包装,且其的实例是不可变的(避免引用传参)。

从 jdk9 起,包装类的构造方法被注解为废弃的,并推荐使用包装类的工厂方法。

It is rarely appropriate to use this constructor. The static factory is generally a better choice, as it is likely to yield significantly better space and time performance.

工厂方法:(以Integer为例)

public static Integer valueOf(int i)
public static Integer valueOf(String s)
public static Integer valueOf(String s, int radix)

该工厂方法也是自动装箱时编译器的默认行为,例如:

list.add(3);

经过编译后相当于:

list.add(Integer.valueOf(3));

自动拆箱会隐式调用:

int intValue()

自动拆箱常发生在算数运算或赋值中:

int n = list.get(i);

相当于:

int n = list.get(i).intValue();

同时包装类也作为一个工具类,对应基础类型相关的工具被封装为静态方法。

static String toString(int i)
// 整数转换为字符串
static String toString(int i ,int radix)
// 整数转换为 radix 进制的字符串

static int parselnt(String s)
// 字符串转换为整数
static int parseInt(String s,int radix) 
// 字符串转换为 radix 进制的整数

枚举类

Java 中的枚举类与 C/C++ 中的枚举类型不太一样,在 Java 中,枚举类是一个类。

通过enum代替class来定义一个枚举类:

enum State {
    
    
    OPEN, CLOSE
}

注意,枚举类不允许在局部作用域下(方法中)定义。

使用枚举类的一般情况:

State flag = State.OPEN;

if(flag == State.CLOSE){
    
    
    // ...
}

这是如何实现的呢?

枚举类会隐式继承Enum类,类初始化时会调用一个私有构造器,构造出所有的public static final实例。

这些实例就是我们定义的枚举常量,这些常量都是对象,所以拥有一些方法:

String name()
String toString()
// 返回字符串表示
    
int ordinal()
// 返回该对象的声明序号

int compareTo(E o)
// 对比声明顺序
    
boolean equals(Object other)
// 可以使用 == 
    
Class<?> getDeclaringClass()
// 返回枚举类的 Class 实例,或其外部类的 Class 实例

除此之外,枚举类作为一个类,允许我们重写方法、定义构造和成员函数。

例如,为每一个枚举常量留一个描述,并允许调用者获取到这个儿描述:

enum State  {
    
    
    OPEN("This instance means that the current state is open"),
    CLOSE("This instance means that the current state is off");
    String desc;
    private State(String aDesc){
    
    
        this.desc = aDesc;
    }
    public String getDesc() {
    
    
        return desc;
    }
};

在来一个例子,我们还可以实现枚举类的实例的多态。

正常情况下,枚举类:

enum State  {
    
    
    OPEN, CLOSE
};

他的原理类似:

class State extends Enum{
    
    
    public static final State OPEN;
    public static final State CLOSE;
    
    private State(String name, int i) {
    
    
        super(name, i);
    }
    
    // 通过类的静态初始化块,实例化出所有枚举类型实例
    static {
    
    
        OPEN = new State("OPEN", 0);
        CLOSE = new State("CLOSE", 1);
    }
}

对于这一部分:

public static final State OPEN;
public static final State CLOSE;

它们也许可以是State的子类,我们可以在 State 中定义一个抽象方法,然后让这些枚举成员继承State并实现抽象方法:

enum State  {
    
    
    OPEN{
    
    
        @Override
        String getDesc() {
    
    
            return "This instance means that the current state is open";
        }
    },
    CLOSE {
    
    
        @Override
        String getDesc() {
    
    
            return "This instance means that the current state is off";
        }
    };
    abstract String getDesc();
};

这一段代码的原理相当于:

class State extends Enum{
    
    
    public static final State OPEN;
    public static final State CLOSE;
    
    private State(String name, int i) {
    
    
        super(name, i);
    }
    
    abstract String getDesc();
    
    // 通过类的静态初始化块,实例化出所有枚举类型实例
    static {
    
    
        OPEN = new State("OPEN", 0){
    
    
            @Override
            String getDesc() {
    
    
                return "This instance means that the current state is open";
            }
    	};
        CLOSE = new State("CLOSE", 1){
    
    
            @Override
            String getDesc() {
    
    
                return "This instance means that the current state is off";
            }
    	};
    }
}

猜你喜欢

转载自blog.csdn.net/qq_16181837/article/details/112294864