面向对象高级(三)
内部类
- 内部类是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类。
- 场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类。比如:汽车类中的发动机类,发动机类就可以设计成内部类。
内部类的分类
成员内部类
-
成员内部类就是类中的一个普通成员,类似于普通的成员变量、成员方法。
-
JDK16之前,成员内部类中不能定义静态成员,JDK16开始成员内部类也可以定义静态成员了。
定义格式
public class Outer {
// 成员内部类
public class Inner {
}
}
创建对象的格式
外部类名.内部类名 对象名 = new 外部类(...).new 内部类(...);
成员内部类中访问其他成员的特点
- 成员内部类的实例方法中,同样可以直接访问外部类的实例成员、静态成员。
- 可以在成员内部类的实例方法中,拿到当前外部类的对象,格式是:外部类名.this 。
静态内部类
静态内部类是有static修饰的内部类,属于外部类自己持有。
定义格式
public class Outer {
// 静态内部类
public static class Inner {
}
}
创建对象的格式
外部类名.内部类名 对象名 = new 外部类.内部类(...);
访问其他成员的特点
可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员。
局部内部类
-
局部内部类是定义在在方法中、代码块中、构造器等执行体中的内部类。
-
鸡肋语法。
定义格式
public class Test {
public static void main(String[] args) {
}
public static void go() {
class A {
}
abstract class B {
}
interface C {
}
}
}
匿名内部类
匿名内部类是一种特殊的局部内部类,所谓匿名就是定义时不需要为这个类声明名字。
定义格式
new 类或接口(参数值...) {
类体(一般是方法重写)
};
特点
匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
作用
用于更方便的创建一个子类对象。
常见使用场景
有时需要一个不常用的类,定义这个类太麻烦,就可以使用匿名内部类,它通常作为一个参数传输给方法。
枚举类
枚举是一种特殊的类。
枚举类的格式
修饰符 enum 枚举类名{
名称1 , 名称2, ...;
其他成员
}
- 枚举类中的第一行,只能写一些合法的标识符(名称),多个名称用逗号隔开。
- 这些名称,本质是常量,每个常量都会记住枚举类的一个对象。
枚举类的特点
- 枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象。
- 枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象。
- 枚举都是最终类,不可以被继承。
- 枚举类中,从第二行开始,可以定义类的其他各种成员。
- 编译器为枚举类新增了几个方法,并且枚举类都是继承:java.lang.Enum类的,从enum类也会继承到一些方法。
枚举类提供的额外的API
方法名 | 说明 |
---|---|
static 枚举类名[] values() | 拿到枚举类的全部对象,放在一个数组中返回 |
public static <T extends Enum<T>> T valueOf(Class<T> enumClass, String name) | 返回具有指定名称的指定枚举类型的枚举常量 |
public final String name() | 返回此枚举常量的名称,与其枚举声明中声明的完全相同 |
public final int ordinal() | 返回此枚举常量的索引(它在枚举声明中的位置,其中初始常量的索引为零) |
抽象枚举
如果枚举类里有抽象方法,此时枚举类里第一行罗列的对象必须重写所有抽象方法(可以使用匿名类)。
可以使用枚举实现单例模式
class enum 类名{
对象名; //单例
}
枚举类的常见应用场景
用来表示一组信息,然后作为参数进行传输。此时有两种方法:
- 选择定义一个一个的常量来表示一组信息,并作为参数传输。此时参数值不受约束,但是代码简洁。
- 选择定义枚举表示一组信息,并作为参数传输。此时代码可读性好,参数值得到了约束,对使用者更友好,但是代码比较复杂。
泛型
认识泛型
定义类、接口、方法时,同时声明了一个或者多个类型变量(如:<E>),这些类、接口、方法就称为泛型类、泛型接口,泛型方法、它们统称为泛型。
作用
泛型提供了在编译阶段约束所能操作的数据类型并自动进行检查的能力。这样可以避免强制类型转换及其可能出现的异常。
本质
把具体的数据类型作为参数传给类型变量。
泛型类
修饰符 class 类名<类型变量1(extends 类名), 类型变量2(extends 类名), ...> {
}
- 类型变量建议用大写的英文字母,常用的有:E、T、K、V 等。
泛型接口
修饰符 interface 接口名<类型变量1(extends 接口名), 类型变量2(extends 接口名), ...> {
}
- 类型变量建议用大写的英文字母,常用的有:E、T、K、V 等。
泛型方法
修饰符 <类型变量1(extends 接口名), 类型变量2(extends 接口名), ...> 返回值类型 方法名(形参列表){
}
泛型通配符
泛型通配符就是“ ? ”,可以在“使用泛型”的时候代表一切类型;与E,T,K,V类似,是在定义泛型的时候使用。
泛型的上下限
- 泛型上限:<? extends Car>,此时接收的必须是Car或者其子类 。
- 泛型下限:<? super Car>,此时接收的必须是Car或者其父类。
泛型的注意事项
- 泛型是工作在编译阶段的,一旦程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除。
- 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)。
- 定义泛型类之后,在类内部使用泛型时不能与static搭配,因为泛型可能会发生变化,而static的成员只有一份。
常用API(一)
API概述
API(Application Programming interface:应用程序编程接口)就是Java帮我们已经写好一些程序,如:类、方法等,我们直接拿过来用就可以解决一些问题。
API有什么用
大大提高开发效率。
常用API
Object | LocalTime | Set | FileOutputStream | Properties |
---|---|---|---|---|
objects | LocalDateTime | HashSet | Reader | Thread |
Integer | Duration | LinkedHashSet | FileReader | Runnable |
StringBuilder | Period | TreeSet | Writer | Callable |
StringBuffer | ZoneId | Map | FileWriter | ExecutorService |
Math | ZonedDateTime | HashMap | BufferdInputStream | ThreadPoolExecutor |
System | Arrays | LinkedHashMap | BufferdOutputStream | Socket |
Runtime | Comparable | TreeMap | BufferedReader | ServerSocket |
BigDecimal | Comparator | Iterator | BufferedWriter | Class |
Date | Collection | Stream | PrintStream | Method |
SimpleDateFormat | List | InputStream | PrintWriter | Constructor |
Calendar | ArrayList | FileInputStream | ObjectInputStream | Field |
LocalDate | LinkedList | OutputStream | ObjectOutputStream | Proxy... |
Object类
Object类是Java中所有类的祖宗类,因此,Java中所有类的对象都可以直接使用Object类中提供的一些方法。
Object类的常见方法
方法名 | 说明 |
---|---|
public String toString() | 返回对象的字符串表示形式。 |
public boolean equals(Object o) | 判断两个对象是否相等。 |
protected Object clone() | 对象克隆 |
-
toString()方法存在的意义就是被子类重写,以便返回对象具体的内容。
-
equals()方法默认是比较两个对象的地址是否相同,但是直接比较两个对象的地址是否相同完全可以用“==”替代equals,equals存在的意义就是为了被子类重写,以便子类自己来定制比较规则(比如比较对象内容)。
-
如果要使类能克隆,则必须实现Cloneable接口
-
clone是浅克隆
克隆
-
浅克隆:克隆出的新对象,与原对象中的数据一模一样(引用类型克隆的只是地址)。
-
深克隆:对象中基本类型的数据直接克隆;对象中的字符串数据克隆的还是地址(由于字符串常量池的存在);若对象中还包含的其他对象,则不会克隆地址,会创建新对象。
Objects类
Objects是一个工具类,提供了很多操作对象的静态方法给我们使用。
Objects类的常见方法
方法名 | 对象 |
---|---|
public static boolean equals(Object a, Object b) | 先做非空判断,再比较两个对象 |
public static boolean isNull(Object obj) | 判断对象是否为null,为null返回true ,反之 |
public static boolean nonNull(Object obj) | 判断对象是否不为null,不为null则返回true, 反之 |
为什么比较两个对象是否相等,要用Objects的equals方法,而不是用对象自己的equals方法来比较呢?
因为Objects的equals()不会报错,更安全。
包装类
包装类就是把基本类型的数据包装成对象,从而可以使用API和泛型来操作这些数据,也可以实现万物皆对象。
Java有以下机制,可以使包装类与基本类型自动转换
自动装箱:可以自动把基本类型的数据转换成对象。
自动拆箱:可以自动把包装类型的对象转换成对应的基本数据类型。
基本数据类型对应的包装类
基本数据类型 | 对应的包装类(引用数据类型) |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |
boolean | Boolean |
基本数据类型包装成对象的方法
public static 包装类 valueOf(基本数据类型 i) {...}
包装类的其他常见操作
可以把基本类型的数据转换成字符串类型:
public static String toString(基本数据类型 d) {...}
public String toString() {...}
String result = variable + ""; //也可以用这种方法
可以把字符串类型的数值转换成数值本身对应的数据类型:
public static 基本数据类型 parse包装类名(Character除外)(String s) {...} //Character类没有parseCharacter()方法
public static 基本数据类型 valueOf(String s) {...}
//必须要是对应的数值类型才能转换,否则会报错
StringBuilder
StringBuilder代表可变字符串对象,相当于是一个容器,它里面装的字符串是可以改变的,就是用来操作字符串的。
好处
StringBuilder比String更适合做字符串的修改操作,效率会更高,代码也会更简洁。
常用构造器
构造器 | 说明 |
---|---|
public StringBuilder() | 创建一个空白的可变的字符串对象,不包含任何内容 |
public StringBuilder(String str) | 创建一个指定字符串内容的可变字符串对象 |
常用方法
方法名称 | 说明 |
---|---|
public StringBuilder append(任意类型) | 添加数据并返回StringBuilder对象本身 |
public StringBuilder reverse() | 将对象的内容反转 |
public int length() | 返回对象内容长度(字符数) |
public String toString() | 通过toString()就可以实现把StringBuilder转换为String |
append()支持链式编程:
StringBuilder s = new StringBuilder("1");
s.append(2).append(3).append(4); //链式编程
为什么要使用StringBuilder,而不用String
效率更高。
-
对于字符串相关的操作,如频繁的拼接、修改等,建议用StringBuilder,效率更高!
-
如果操作字符串较少,或者不需要操作或者定义字符串变量,还是建议用String。
StringBuffer
-
StringBuffer的用法与StringBuilder是一模一样的。
-
但StringBuilder是线程不安全的,而StringBuffer是线程安全的。
StringJoiner
StringJoiner是JDK8开始才有的,跟StringBuilder一样,也是用来操作字符串的,也可以看成是一个容器,创建之后里面的内容是可变的。
好处
不仅能提高字符串的操作效率,并且在有些场景下使用它操作字符串,代码会更简洁。
常用构造器
构造器 | 说明 |
---|---|
public StringJoiner(间隔符号) | 创建一个StringJoiner对象,指定拼接时的间隔符号 |
public StringJoiner(间隔符号,开始符号,结束符号) | 创建一个StringJoiner对象,指定拼接时的间隔符号、开始符号和结束符号 |
常用方法
方法名称 | 说明 |
---|---|
public StringJoiner add(添加的内容) | 添加数据,并返回对象本身,支持链式编程 |
public int length() | 返回长度(字符数) |
public String toString() | 返回一个字符串(该字符串就是拼接之后的结果) |