面向对象高级
1、接口interface
1、接口中可以有什么?
jdk8之前,只能有:
- 公共的静态的常量:其中 public static final 可以省略
- 公共的抽象的方法:其中 public abstract 可以省略
jdk8及以后:还可以声明默认方法(用default修饰,不能省略default也不能省略方法体)和静态方法
(接口中声明的静态方法只能使用“接口名.”进行调用,不能通过实现类的对象进行调用)
(9.0新增了私有方法)
没有构造器,没有初始化块
2、java类不能多继承,可以多实现
c++可以多继承,java一个类只能继承一个父类。为了弥补这个问题,java支持多实现,即一个类可以实现多个接口。
接口不能创建对象,但是可以被类实现(implements ,类似于被继承)实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements 关键字
1 2 3 4 5 6 7
| class A extends SuperA implements B,C{ }
|
3、接口可以多继承
接口与接口是继承关系,而且可以多继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public interface AA { void method1(); } public interface BB { void method2(); }
public interface CC extends AA,BB { void eat(); }
public class type implements CC { @Override public void eat() { System.out.println("阿巴阿巴阿巴\n"); } @Override public void method2() { System.out.println("阿巴阿巴阿巴\n"); } @Override public void method1() { System.out.println("阿巴阿巴阿巴\n"); } }
|
4、接口与实现类对象构成多态引用
实现类实现接口,类似于子类继承父类,因此,接口类型的变量与实现类的对象之间,也可以构成多态引用。通过接口类型的变量调用方法,最终执行的是我们new的实现类对象实现的方法体。
5、接口中属性和方法的调用
1.接口的静态成员
接口不能直接创建对象,但是可以通过接口名直接调用接口的静态方法和静态常量。
2.接口的静态方法
接口中声明的静态方法只能使用“接口名.”进行调用,不能通过实现类的对象进行调用
3.接口的抽象/默认方法
- 对于接口的抽象方法、默认方法,只能通过实现类对象才可以调用
6、jdk8冲突问题
6.1 默认方法冲突问题
(1)类优先原则
当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的抽象方法重名,子类就近选择执行父类的成员方法。
如果子类重写了这个方法,调用父类用super.
,调用某个接口的那个同名方法用接口名.super.方法名()
(如果那个接口中那个方法是静态的可以直接接口名.方法名()
)
2、内部类
1、创建内部类的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Person { static class dog { } class bird { } } public class OuterClassTest { Person.Dog dog = new Person.Dog(); Person p1 = new Person(); Person.Bird bird = p1.new Bird(); }
|
2.内部类命名冲突
其实不算是冲突,只是覆盖了,能正常编译运行的。
1.属性命名冲突
1 2 3 4 5 6 7 8 9 10 11 12
| Class Person { String name = "Tom"; int age; class Bird { String name = "企鹅"; public void show(String name) { System.out.println("age = " + this.name); System.out.println("age = " + Person.this.name); } } }
|
2.方法命名冲突
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| Class Person { public void eat() { System.out.println("人吃蘑菇"); } class Bird { String name = "企鹅"; public void eat() { System.out.println("企鹅不吃萝卜"); } public void show() { eat(); this.eat(); Person.this.eat(); } } }
|
3、匿名类
1. 提供一个继承与Object的匿名子类的匿名对象
1 2 3 4 5 6 7 8 9 10
| public class InnerClassTest1 { public static void main(String[] args) { new Object() { public void whoami() { System.out.println("id = 1000, name = \"QAQ\"" + "\n"); } }.whoami(); System.out.println("ciallo~"); } }
|
4、枚举类
1、jdk5.0之前
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public class Season { private final String seasonName; private final String seasonDesc; private Season(String seasonName, String seasonDesc) { this.seasonDesc = seasonDesc; this.seasonName = seasonName; }
public String getSeasonName() { return seasonName; }
public String getSeasonDesc() { return seasonDesc; } public static final Season SPRING = new Season("清明宜晴","谷雨宜雨"); public static final Season SUMMER = new Season("白露种高山","秋分种平原"); public static final Season AUTUMN = new Season("枯骨生荒草","丘壑化桑田"); public static final Season WINTER = new Season("把你种进土里","你重新长吧");
} class Main { public static void main(String[] args) { System.out.println(Season.SPRING); } }
|
当我们在Java中使用System.out.println()
打印对象时,实际上会调用该对象的toString()
方法来获取其字符串表示形式,并将其输出到控制台。
Java中的每个类都继承了Object
类,而Object
类中包含了一个默认的toString()
方法的实现。这个默认实现返回的是类名和对象的哈希码的组合,形式为ClassName@HashCode
。
一般在自己的类中重写toString()方法,如此可以根据自己的需求定义对象的字符串表示形式,以便更好地理解和调试你的代码。这在调试和日志记录时特别有用,因为你可以更清楚地了解对象的状态和内容。
2、jdk5.0新增了enum
使用enum关键字定义的枚举类,默认其父类是java.lang.Enum类
使用enum关键字定义的枚举类,不要显示地定义其父类,否则报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class SeasonTest2 { public static void main(String[] args) { System.out.println(SeasonTest1.WINTER); } } enum SeasonTest1 { SPRING("清明宜晴","谷雨宜雨"), SUMMER("白露种高山","秋分种平原"), AUTUMN("枯骨生荒草","丘壑化桑田"), WINTER("把你种进土里","你重新长吧");
private final String seasonName; private final String seasonDesc; private SeasonTest1(String seasonName, String seasonDesc) { this.seasonDesc = seasonDesc; this.seasonName = seasonName; }
public String getSeasonName() { return seasonName; }
public String getSeasonDesc() { return seasonDesc; }
}
|
枚举常量已经预定义了,因此不需要创建对象。枚举常量本身就是枚举类型的实例(也就是说她们本身就是对象)。打印枚举常量时,默认情况下会调用枚举类的toString()
方法。
对于枚举类型,默认的toString()
方法已经被重写,它返回枚举常量的名称,而不是类名和哈希码的组合。因此,在代码中,当打印SeasonTest1.WINTER
时,它只会打印枚举常量的名称,即WINTER
。
3、enum类的常用方法
1.toString()
String toString()返回当前枚举常量的名称
2.name()
String name()得到当前对象名称
3.values()
static 枚举类型[] values()
返回枚举类型的对象数组,该方法可以便捷地遍历所有的枚举值
1 2 3 4 5 6
| SeasonTest1[] values1 = SeasonTest1.values(); for(int i = 0; i < values1.length; i++) { System.out.println(values1[i]); }
|
4.valueOf(String sbjName)
返回当前枚举类中名称为objName的枚举类对象
如果枚举类中不存在objName名称的对象,则报错。
1 2 3
| String objName = "WINTER"; SeasonTest1 season1 = SeasonTest1.valueOf(objName);
|
5.name()
String name()得到当前枚举常量的名称,建议优先使用toString()
6.ordinal()
int ordinal()
返回当前枚举常量的次序号,从0开始。
4、实现接口的枚举类
- 和普通 Java 类一样,枚举类可以实现一个或多个接口
- 若每个枚举值在调用实现的接口方法呈现相同的行为方式,则只要统一实现该方法即可。
- 若需要每个枚举值在调用实现的接口方法呈现出不同的行为方式,则可以让每个枚举值分别来实现该方法
5、开发中常用的写法
以下为同一个包的三个文件
1 2 3
| public enum Season3 { SPRING,SUMMER,AUTUMN,WINTER; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public class XI { private Season3 season3; private int age; public XI() { }
public XI(Season3 season3, int age) { this.season3 = season3; this.age = age; }
public Season3 getSeason3() { return season3; }
public void setSeason3(Season3 season3) { this.season3 = season3; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override public String toString() { return "xi{" + "season3=" + season3 + ", age=" + age + '}'; } }
|
1 2 3 4 5 6
| public class Enum2Test { public static void main(String[] args) { XI xibao = new XI(Season3.SPRING,37); System.out.println(xibao); } }
|
5、 JUnit单元测试
1、需要的jar包
1 2
| junit-4.12.jar hamcrest-core-1.3.jar
|
2.正确的单元测试方法
- 所在类必须是公共的、非抽象的,且包含唯一的无参构造器(其实不写构造器就符合这个要求了)
- @Test标记的方法本身必须是公共的、非抽象的、非静态的,无返回值,无参数的
但是对于它调用的方法没有那么多限制
3.设置执行JUnit用例时支持控制台输入
工具栏:help - Edit Custom VM Options
在结尾加上
1
| -Deditable.java.test.console=true
|
添加完成之后,重启IDEA即可。
如果上述位置设置不成功,需要继续修改如下位置
修改位置1:IDEA安装目录的bin目录(例如:D:\develop_tools\IDEA\IntelliJ IDEA 2022.3.2\bin
)下的idea64.exe.vmoptions文件。
修改位置2:C盘的用户目录C:\Users\用户名\AppData\Roaming\JetBrains\IntelliJIdea2022.3
下的idea64.exe.vmoptions`件。
4.定义test测试方法模板
设置-Editor-Live Template 点击”+”来定义模板。
(建议先新增组再新增模板)

$var1$ 模版引入时光标的位置
$END$敲回车之后光标的位置
记得点下面蓝色的 Define按钮更改应用范围