“别担心,你一定能如愿。”
—— 24.4.29
1.什么时候使用内部类:
当一个事物的内部,还有一个部分需要完整的结构去描述,而内部的完整结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类
比如:人类有心脏,人类本身需要用属性、行为去描述,那么人类内部的心脏也需要心脏特殊的属性和行为去描述,此时心脏就可以定义成内部类,人类中的一个心脏类
2.在java中允许一个类的定义位于另外一个类的内部,前者被称之为内部类,后者被称之为外部类
class A{
class B{
}
}
类A就是类B的外部类
类B就是类A的内部类
3.分类:
成员内部类(静态,非静态)
局部内部类
匿名内部类(重点)
一、静态成员内部类
1.格式:
直接在定义内部类的时候加上static关键字
public class A{
static class B{
}
}
2.注意:
a、内部类可以定义属性、方法、构造等
b、静态内部类可以被final或者abstract修饰
被final修饰之后,不能被继承
被abstract修饰之后,不能new
c、静态内部类不能调用外部的非静态成员
d、内部类还可以被四种权限修饰符修饰
二、成员内部类
1.调用静态成员内部类
外部类.内部类 对象名 = new 外部类.内部类()
public class Person { public void eat(){ System.out.println("人要干饭"); } static class Heart{ public void jump(){ System.out.println("心脏跳动"); } } }
public class Demo134StaticInnerClass { public static void main(String[] args) { // 外部类.内部类 对象名 = new 外部类.内部类() Person.Heart heart = new Person.Heart(); heart.jump(); } }
2.调用非静态成员内部类
外部类.内部类 对象名 = new 外部类().new 内部类()
Person外部类,Heart内部类,jump内部类Heart里的方法
public class Person { public void eat(){ System.out.println("人要干饭"); } class Heart{ Heart(){ } public void jump(){ System.out.println("心脏跳动"); } } }
public class Demo135StaticInnerClass2 { public static void main(String[] args) { // 外部类.内部类 对象名 = new 外部类().new 内部类() Person.Heart heart = new Person().new Heart(); heart.jump(); } }
外部类的成员变量和内部类的成员变量以及内部类的局部变量重名时,怎么区分?
示例:
外部类Student 内部类Heart 内部类的方法display
public class Student { String name = "金莲"; class Heart{ String name = "大朗"; public void display(String name){ // 内部类的局部变量 System.out.println(name); // 内部类的成员变量 System.out.println(this.name); // 外部类的成员变量 System.out.println(Student.this.name); } } }
测试类
public class Demo136StaticInnerClass3 { public static void main(String[] args) { Student.Heart heart = new Student().new Heart(); heart.display("小明"); } }
三、局部内部类
1.局部内部类的基本操作
可以定义在方法中、代码块中、构造方法中
示例:
Person外部类和Heart内部类
public class Person { public void eat(){ class Heart{ public void jump(){ System.out.println("心脏哐哐哐的跳动"); } } new Heart().jump(); } }
测试类
public class Demo137StaticInnerClass4 { public static void main(String[] args) { Person person = new Person(); person.eat(); } }
2.局部内部类实际操作
1.接口类型作为方法参数传递和返回
接口作为方法参数,传递实参时,传递的是实现类对象
示例:
接口
public interface USB { public abstract void open(); }
实现类
public class Mouse implements USB{ @Override public void open() { System.out.println("鼠标打开"); } }
测试类
public static void main(String[] args) { Mouse mouse = new Mouse(); method(mouse); System.out.println("————————————————————————"); // USB usb = new Mouse(); USB usb = method01(); usb.open(); } /* 接口作为方法参数返回,实际返回的是实现类对象 USB usb = mouse ——> 多态 */ public static void method(USB usb){ usb.open(); } /* 接口作为返回值类型,传递实参时,传递的是实现类对象 */ public static USB method01(){ Mouse mouse = new Mouse(); return mouse; //return new Mouse(); } }
2.抽象类作为方法参数和返回值
① 抽象类作为方法参数传递,传递实参时,传递的是其子类对象
② 抽象类作为方法返回值类型返回时,实际返回的是其子类对象
示例:
抽象类
public abstract class Animal { public abstract void eat(); }
实现类
public class Dog extends Animal{ @Override public void eat() { System.out.println("狗啃骨头"); } }
测试类
public class Demo139StaticInnerClass6 { public static void main(String[] args) { Dog dog = new Dog(); method01(dog); System.out.println("————————————————————"); Animal animal = method02(); animal.eat(); } public static void method01(Animal animal){ animal.eat(); } public static Animal method02(){ Dog dog = new Dog(); return dog; } }
3.普通类做方法参数和返回值
普通类作为方法参数传递,传递的是对象
普通类作为方法返回值返回,返回的是对象示例:
普通类
public class Person { public void eat(){ System.out.println("人要吃饭"); } }
测试类
public class Demo140StaticInnerClass7 { public static void main(String[] args) { Person person = new Person(); method01(person); System.out.println("————————————————————————"); Person person1 = method02(); method01(person1); } public static void method01(Person person){ person.eat(); } public static Person method02(){ Person person = new Person(); return person; } }
4.局部内部类实际操作
USB接口
public interface USB { void open(); }
测试类
public class Demo141StaticInnerClass8 { public static void main(String[] args) { // USB usb = new Mouse() USB usb = method(); usb.open(); } public static USB method(){ // 局部内部类 class Mouse implements USB { @Override public void open() { System.out.println("鼠标打开了"); } } Mouse mouse = new Mouse(); return mouse; } }
四、匿名内部类⭐
1.定义
所谓的匿名内部类:可以理解为没有显式声明出类名的内部类
2.问题描述
我们如果想实现接口,简单使用一次抽象方法,我们就需要创建一个实现类,实现这个接口,重写抽象方法,还要new实现类对象,如果我们单纯使用一次接口中的方法,我们能否不这么麻烦进行实现吗?
a、创建实现类,实现接口
b、重写方法
c、创建实现类对象
d、调用方法
3.单纯使用接口方法
如果我们想单纯使用一下接口中的方法,我们可以四步合一
4.匿名内部类学习方法
按照一种格式来学习,这一种格式代表了实现类对象或是子类对象
5.格式
实现类对象
①:
new 接口/抽象类(){
重写方法
}.重写的方法():
②:
类名 对象名 = new 接口/抽象类(){
重写方法
}
对象名.重写的方法
public class Demo142StaticInnerClass9 { public static void main(String[] args) { // 重写接口方法 new USB() { @Override public void open() { System.out.println("USB打开了"); } @Override public void close() { System.out.println("USB关闭了"); } }.open(); System.out.println("——————————————————————————————————————"); // 有名对象,可以调用多个方法 USB usb = new USB() { @Override public void open() { System.out.println("USB打开了"); } @Override public void close() { System.out.println("USB关闭了"); } }; usb.open(); usb.close(); } }
将抽象方法和创建实现类对象调用抽象方法合二为一:
6.总结
1.什么时候使用匿名内部类?
当简单调用一次接口中的方法,我们就可以使用匿名内部类
2.将一种格式代表实现类对象或者子类对象来学习
3.匿名内部类会编译生成的,我们只需要利用讲的格式去new对象,调用重写的方法即可
7.匿名内部类的复杂使用_当参数传递
接口
public interface USB { // 定义一个抽象方法 void open(); }
测试类
public class Demo143StaticInnerClass10 { public static void main(String[] args) { method01(new USB() { @Override public void open() { System.out.println("USB打开了"); } }); } public static void method01(USB usb){ usb.open(); } }
实现流程
8.匿名内部类的复杂使用_当返回值返回
接口
public interface USB { // 定义一个抽象方法 void open(); }
测试类
public class Demo144StaticInnerClass11 { public static void main(String[] args) { USB usb = method01(); usb.open(); } public static USB method01(){ return new USB() { @Override public void open() { System.out.println("USB打开了"); } }; } }
实现流程
五、总结
1.权限修饰符
①属性:用 private -> 封装思想
②成员方法:用 public -> 便于调用
③构造public:便于new对象
2.final关键字
①修饰类
a、格式:public final class 类名
b、特点:不能被继承
②修饰方法
a、格式:修饰符final 返回值类型 方法名(形参){}
b、特点:不能被重写
c、注意:final和abstract不可以同时使用
③修饰局部变量
a、格式:final 数据类型 变量名 = 值
b、特点:不能二次赋值
④修饰对象
a、格式:final 类型 对象名 = new 对象()
b、特点: 地址值不能变,但是对象中的属性值可以改变
⑤修饰成员变量
a、格式:final 数据类型 变量名 = 值
b、特点:需要手动赋值,不能二次赋值
3.代码块
①构造代码块
a、格式: { 代码 }
b、执行特点:优先于构造方法执行,每new一次就执行一次
②静态代码块
a、格式: static{ 代码 }
b、执行特点:优先于构造代码块和构造方法执行,且只执行一次
4.内部类
①静态成员内部类
外部类.内部类.对象名 = new 外部类.内部类()
②非静态成员内部类
外部类.内部类.对象名 = new 外部类().new 内部类()
③局部内部类
⭐ 匿名内部类
格式1:
new 接口/抽象类(){
重写方法
}.重写的方法():
格式2:
类名 对象名 = new 接口/抽象类(){
重写方法
}
对象名.重写的方法
注意:
学习:一个格式代表实现类对象或者子类对象