重要内容
-
匿名内部类的使用方式(明确什么时候可以用,匿名内部类的底层原理)
-
枚举的定义方式与基本使用
内部类
内部类:是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类。
内部类、成员内部类(了解)
内部类的概述:
当一个类的内部定义了一个类,那么里面的这个类就是内部类!
成员内部类:
就是在类的内部定义了一个新的类,就是类中的一个普通成员。
public class Outer {
//成员内部类
public class Inner{
//代码块
}
}
创建对象的格式:
//外部类名.内部类名 对象名 = new 外部类(...). new 内部类(...);
Outer.Inner in = new new Outer().new Inner();
成员内部类的使用方式:
public class Person {
private String name;
private int age;
//每个人都有心脏Heart(心脏本质上是一个完整的事物,但是心脏在人体的内部) 可以声明为人类的内部类(普通成员内部类)
public class Heart {
//内部类和正常类是一模一样的,该定义成员变量,成员方法,构造方法!
int count; //心脏每分钟跳动的次数
public void showCount() {
//内部是可以随意访问外部类的内容的,不重名的情况下可以直接使用名称访问,重名冲突的情况下,默认就近原则(局部/内部类/外部类)
//使用外部类名.this表示外部类对象,this表示内部类对象
System.out.println(Person.this.name + "的年龄是" + Person.this.age + "岁,当前心脏每分钟跳动的次数是" + this.count + "次!");
}
public Heart() {
if (age >= 1 && age <= 6)
this.count = 60;
else if (age >= 7 && age <= 18)
this.count = 90;
else if (age >= 19 && age <= 60)
this.count = 99;
else if (age >= 61 && age <= 120)
this.count = 50;
else
this.count = 0;
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
创建内部类的对象:
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
Person.Heart heart = new Person("小明", 23).new Heart();
静态内部类
静态内部类就是成员内部类的一种。
静态内部类定义格式:
public class Outer {
//实例方法
public void show() {
System.out.println("Outer的show方法执行了!");
}
//静态方法
public static void function() {
System.out.println("Outer的静态function方法执行了!");
}
//静态内部类
public static class Inner {
//内部类的实例方法(需要基于内部类对象调用)
public void method() {
function(); //静态内部类可以访问外部类的静态内容,不能访问实例内容
}
//内部类的静态方法(基于内部类名来调用)
public static void staticMethod(){
function();
}
}
}
静态内部类的使用方式:
外部类名.内部类名 变量名 = new 外部类名.内部类名();
//创建静态内部类对象
Outer.Inner i = new Outer.Inner();
i.method();//实例方法
Outer.Inner.staticMethod(); //静态方法
局部内部类
局部内部类的格式:
public class InnerDemo3 {
public static void main(String[] args) {
//局部内部类定义在方法中/代码块中/构造方法中(特点:在方法执行过程中必须完成类的声明和类的使用) 鸡肋!
class A {
public void show() {
System.out.println("局部内部类A的实例方法show方法执行了!");
}
}
A a = new A();
a.show();
}
}
局部内部类的基本使用:
如果定义在实例方法中,可以访问外部类的所有内容,如果定义在静态方法中,只能访问外部类的静态内容。
匿名内部类
匿名内部类的格式:
new 抽象父类/接口(){
//针对于抽象父类/接口的方法重写
}
匿名内部类的本质:
本质上抽象父类/接口(){}这个部分就是编写好逻辑的一个子类/实现类,前面的new表示创建一个子类/实现类对象。
总结为一句话:匿名内部类就是指定的抽象父类/接口的子类对象(带有完整实现逻辑)。
匿名内部类的使用前提与快捷方式
(1)当方法的参数是一个接口/抽象父类,快速传递一个带有指定逻辑的子类对象/实现类对象作为参数的时候。
可以考虑匿名内部类。
匿名内部类就是作为一个参数去传递的!
(2)如果抽象父类/接口中的方法过多,不建议使用!由于匿名内部类是一次性的,少量的方法可以用,要实现的方法过多,建议还是新建一个具体的类挨个实现之后提高复用性!
让代码编写更灵活,不需要死板的新建类,实现接口,实现方法,创建对象!
(3)匿名内部类在使用的时候,如果明确要作为哪个抽象父类或者接口的对象,那么直接在传递参数的时候new,根据提示选择即可快速生成!
枚举
枚举:保证一个类的对象是有限的。
枚举的定义格式
public enum 枚举类名 {
枚举项名(对象名),枚举项名(对象名),枚举项名(对象名);
//和其他类一样声明成员方法,成员变量,不建议生成构造方法(默认也是私有的)
}
例子
public enum Season {
//通过分析明确Season创建4个对象就足够,分别表示春夏秋冬!
//枚举项一般被static final修饰,也就是常量。
SPRING, SUMMER, AUTUMN, WINTER; //public static final Season SPRING = new Season();
//剩余的部分(和正常类一样) 生成成员变量,生成成员方法。
public void goWhere() {
System.out.println("去哪里!");
}
//构造不推荐生成(枚举的构造默认是私有的)
}
public class SeasonTest {
public static void main(String[] args) {
//获取枚举项之后就作为一个普通对象进行使用。
Season.SPRING.goWhere();
//作为参数传递(和多态没有关系)=>当发现方法的参数是枚举的时候,本质上传递的是枚举项(枚举的一个对象)。
go(Season.SPRING);
go(Season.SUMMER);
go(Season.AUTUMN);
go(Season.WINTER);
}
public static void go(Season season) {
switch (season) {
case SPRING:
System.out.println("春天应该去郊游!");
break;
case SUMMER:
System.out.println("夏天应该去游泳!");
break;
case AUTUMN:
System.out.println("秋天应该去吃水果!");
break;
case WINTER:
System.out.println("冬天应该去滑雪!");
break;
}
}
}
当想要获取到枚举类中的某一个枚举项,就按照枚举类名.枚举项名访问即可获取到该对象。
获取到该对象之后,本质上就是个对象,基于对象调用方法、作为参数传递。
枚举单例模式是最安全的单例模式。
枚举的注意事项
(1)枚举类的第一行必须用于声明枚举类的对象的名称,不能干别的。
(2)枚举的构造不需要手动生成,即便生成了默认也是私有的。
(3)枚举类都是最终的不可以继承。
枚举单例模式格式:
public enum Sason{
SPRING;
}
既能防止之后的反射破坏,也可以防止序列化破坏,也可以在多线程环境下安全(不好点:饿汉式)。