Class design and characteristics
Class design
Hide data
For the encapsulation of the class, when designing the class, you should avoid developing the data field directly. In order to ensure that developers do not depend on our underlying details, the data field should be hidden (because there is no guarantee that the data form will not change) and a stable interface should be provided.
When necessary, accessors and changers will be provided to protect the data.
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;
}
Reference type:
Returning a reference is equivalent to directly exposing the data. This should be avoided. We can return a copy.
public String getName() {
return this.name.clone();
}
However, there String
is no such concern as it String
is immutable.
Factory method
When a class is sufficiently complex, using factory methods to construct instances may be a better solution.
For example, this class has multiple subclasses according to different functions. In this case, you can use factory methods and return new instances in polymorphic form.
unit test
Any class can have a main
method, and since any main
method can be used as the entry point of a Java program, we can conveniently perform unit tests.
For example, if we want to test class A, we should implement a main
method in class A and then java A
run the test.
Variable parameter method
Like a printf
function in C/C++ , enter any number of parameters.
In Java, you only need to use the following syntax:
void method(Object...args) {
for(Object obj : args) {
// ... obj
}
}
From the perspective of the implementer, there is no difference from the behavior of Object...
one Object[]
.
From the perspective of the caller, any number of parameters can be passed in.
Packaging
The packaging class is a basic type of packaging, and its instance is immutable (avoid passing by reference).
Starting from jdk9, the construction method of the packaging class is annotated as obsolete, and it is recommended to use the factory method of the packaging class.
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.
Factory method: (take Integer
an example)
public static Integer valueOf(int i)
public static Integer valueOf(String s)
public static Integer valueOf(String s, int radix)
This factory method is also the default behavior of the compiler during autoboxing, for example:
list.add(3);
After compilation, it is equivalent to:
list.add(Integer.valueOf(3));
Automatic unboxing will implicitly call:
int intValue()
Automatic unboxing often occurs in arithmetic operations or assignments:
int n = list.get(i);
Is equivalent to:
int n = list.get(i).intValue();
At the same time, the packaging class is also used as a tool class, and tools related to the corresponding basic type are encapsulated as static methods.
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 进制的整数
Enumeration class
The enumeration class in Java is not the same as the enumeration type in C/C++. In Java, the enumeration class is a class.
Define an enumeration class by enum
replacing class
:
enum State {
OPEN, CLOSE
}
Note that enumeration classes are not allowed to be defined in local scope (in methods).
The general situation of using enumeration classes:
State flag = State.OPEN;
if(flag == State.CLOSE){
// ...
}
How is this achieved?
The enumeration class implicitly inherits the Enum
class, and a private constructor is called when the class is initialized to construct all the public static final
instances.
These instances are the enumeration constants we defined. These constants are all objects, so they have some methods:
String name()
String toString()
// 返回字符串表示
int ordinal()
// 返回该对象的声明序号
int compareTo(E o)
// 对比声明顺序
boolean equals(Object other)
// 可以使用 ==
Class<?> getDeclaringClass()
// 返回枚举类的 Class 实例,或其外部类的 Class 实例
In addition, as a class, the enumeration class allows us to override methods, define constructs and member functions.
For example, leave a description for each enum constant and allow the caller to get this description:
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;
}
};
In an example, we can also achieve polymorphism of instances of enumeration classes.
Under normal circumstances, the enumeration class:
enum State {
OPEN, CLOSE
};
His principle is similar:
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);
}
}
For this part:
public static final State OPEN;
public static final State CLOSE;
They may be State
subclasses, we can define an abstract method in State, and then let these enumeration members inherit State
and implement the abstract method:
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();
};
The principle of this piece of code is equivalent to:
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";
}
};
}
}