面向对象高级语法
1 内部类
1.1 成员内部类
1.1.1 作用
在描述一个类的时候, 如果需要同时描述这个类的某一部分, 而且只用一次的情况下, 没必要另外创建一个类时, 可以使内部类来实现
1.1.2 格式
public class Outer{
public class Inner{
}
}
//如, 这里有一个在Animal 内部的 Cat类
class Animals{
xxxxx
class Cat{
xxxxx
}
}
1.1.3 特点
内部类中可以定义普通的所有的数据
1.1.4 创建对象
Outer.Inner 对象名 = new Outer().new Inner();
还拿上文中Animal的例子
Animals.Cat cat = new Animals("Tiger"). new Cat(21);
可以理解为先拿取Animals的所在位置, 然后通过Animals内部的地址指向存在堆中另一块Cat类
1.1.5 使用
可以使用外部类中所有的数据, 静态成员和实例成员.
内部类的实例方法中,可以通过外部类.this访问外部类对象.
成员内部类 ==> 调用内部类 -> this.xx 外部类->外部类.this.xx
如:
public void eat(){
System.out.println("猫吃狗!");
System.out.println(getAge()+" "+Animals.this.getName());
}
//我的内部类Cat中的方法调用了Outer类的Animals.this.getName, 结果调出为Tiger.
1.2 静态内部类
1.2.1 作用
在描述一个类的时候, 如果需要同时描述这个类的某一部分, 可以使内部类来实现
1.2.2 格式
public class Outer{
public static class Inner{
}
}
1.2.3 特点
内部类中可以定义普通的所有的数据
1.2.4 创建对象
Outer.Inner 对象名 = new Outer.Inner();
1.2.5 使用
可以使用外部类的静态成员. 不能访问实例成员, 这点和静态变量/方法很相似
1.3 局部内部类
很少用, 没咋关注.... 有用到再补充吧
1.4 匿名内部类(开发中常用)
1.4.1 作用
便于创建子类对象
1.4.2 格式
包括一个接口或者抽象类 和 构造匿名内部类指令
1) 构造一个接口或抽象类
// 接口1
public interface SteeringWheel {
void steer();
}
2) 构造匿名内部类指令
格式:
new 抽象类()/接口(){
重写抽象方法
}
一号例子, 构建匿名内部类:
public class Car {
public static void main(String[] args) {
// 构建匿名内部类
// 构建道奇
SteeringWheel dodge = new SteeringWheel() {
@Override
public void steer() {
System.out.println("道奇开始转动");
}
};
// 构建法拉利
SteeringWheel Ferrari = new SteeringWheel() {
@Override
public void steer() {
System.out.println("法拉利开始转动");
}
};
// 调用rt函数
raceTest(dodge);
raceTest(Ferrari);
}
// rt函数, 测试
public static void raceTest(SteeringWheel s){
s.steer();
}
}
还有一种类型,直接把匿名内部类当做方法的参数:
public interface USB {
void plugin();
void out();
}
public class Computer {
public void use(USB usb){
usb.plugin();
usb.out();
}
}
public class test {
public static void main(String[] args) {
Computer c = new Computer();
c.use(new USB() {
@Override
public void plugin() {
System.out.println("keyboard in ");
}
@Override
public void out() {
System.out.println("keyboard out");
}
});
}
}
1.4.3 特点
匿名内部类本质就是一个子类,并会立即创建出一个子类对象。
1.4.4 优点
简化了类的创建,通过匿名内部类可以直接获取到一个子类对象, 也弥补了接口, 抽象类不能构造一个对象的缺点. 将会和接口配合在实际运用中多次出现.
1.4.5 使用场景
一般用于作为参数传递给方法, 如果某一个子类只需要使用一次, 我们就可以使用匿名内部类简化类的创建.
2 枚举
2.1 概念
枚举是一种特殊类, 第一行只能定义变量名称 (实际上是一个用final修饰的常量, 所以不能修改)
2.2 格式
public enum 枚举类名{
变量A,变量B,变量C;
}
例子:
// 枚举
public enum Team {
// 枚举了几只队伍
TeamA, TeamK, TeamB, Team4, Team8;
}
2.3 特点
1) 枚举类中的第一行, 只能写一些合法的标识符(名称), 多个名称用逗号隔开。
2) 普通类能定义的数据,在枚举中都能定义 (类的五大成员)
2.4 使用格式
枚举类名.变量名 (尝试修改会显示枚举中变量被final修饰符修饰, 所以这玩意实际上就是一个常量), 如上文的Team.Team8 就可以读取Team8.
ENUM // value of 字符串转换对象 // values 所有内部转换成对象
运用到例子如下.
public class FindWinner {
//用switch进行调用枚举结果
public static void main(String[] args) {
System.out.println(Team.Team8);
place(Team.Team8);
place(Team.TeamB);
}
private static void place(Team team) {
switch (team){
case Team8 ->
System.out.println("T8 no.1");
case TeamB -> System.out.println("Tb no.2");
}
}
}
2.5 优点
1) 可以限制别人输入的数据
2) 可阅性好
2.6 使用场景
可以结合switch使用, 同时可以用来做一些信息的标记
3 泛型
3.1 作用
泛型提供了在编译阶段约束所能操作的数据类型, 并自动进行检查的能力. 比如 只能接受Animal不接受Animal的子类
3.2 好处
这样可以避免强制类型转换, 及其可能出现的异常。
3.3 泛型的本质
把具体的数据类型作为参数传给类型变量。
3.4 通配符
就是 “?” ,可以在“使用泛型”的时候代表一切类型
除通配符之外, 还能用字母表示泛型 (默认规则, 可以不遵循)
T:代表任意类 E:表示Element的意思,或是异常 K:与V搭配使用 V:与K搭配使用
3.5 泛型上限
泛型上限: ? extends 父类: ? 能接收的必须是自己或者其子类 , 上限get. 用在频繁获取数据的场景
所获取到的只能是本类或子类. 比如<? extends Car> , 只能获取比Car类还小的, 所以称之为上限
3.6 泛型下限
泛型下限: ? super 子类 : ? 能接收的必须是本身或者其父类, 下限add, 用在频繁添加数据的场景
所获取到的只能是本类或父类. 比如<? super Car> , 只能获取比Car类还大的, 所以称之为下限
3.7 注意事项
1) 泛型只停留在编辑器, 编写class文件中的泛型会消失, 变成指代类型, 这一个现象叫做泛型擦除
2) 泛型只能是引用数据类型 (基本数据类型需要设置包装类, 例如int=>integer)
4 API
4.1 Object
4.1.1 toString()
作用是返回对象的地址
可以被重写, 重写后, 可以用于返回对象的具体内容
重写范例:
import java.util.Objects;
//定义一个学生类,里面定义姓名和年龄两个属性。重写toString()方法,改变输出对象时的内容
public class Student {
private String name;
private int age;
public String toString(){
if(Objects.nonNull(getName())&&Objects.nonNull(getAge())){
String b= "姓名是:"+getName()+"\n年龄是:"+getAge();
return b;
}
return "不能输入空";
}
public class test {
public static void main(String[] args) {
Student stu = new Student("Yui", 21);
String str = stu.toString();
System.out.println(str);
}
}
4.1.2 equals()
用于比较两个对象的地址
重写后可以用来比较两个对象的具体内容
4.1.3 clone()
注意clone的修饰符是protected (本类, 同包, 子孙类) , 并不能用于Object子类对象中, 只能用于Object子类. 但是可以通过重写更改修饰符, 并实现一个Cloneable的接口, 用来作为标记. (抛出异常CloneExce...., 添加一个 implements Cloneable (作为标识))
浅克隆: 复制一个一模一样的对象; 即, 基本类型=>具体值, 引用数据类型=>地址值;
深克隆:基本数据类型=>具体值, 字符串=>地址值, 其他引用类型(对象)=>先创建新的对象,在赋值到新的对象中 (创建了新对象).
4.2 Objects
主要用来做一些检查.
笔者PS: 类加s通常为工具类, 即里面用静态方法和匿名构造器的类
常用API有以下
1) equals(Object o1, Object o2) -- 先判断空,再对内容进行判断
2) isNull(Object obj) -- 判断对象是否为空
3) nonNull(Object obj) -- 判断对象是否不为空