1. 概念:
- 在一个 类的内部 再定义一个完整的类。
2. 分类:
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
3. 特点:
- 编译之后,可生成独立的字节码文件。
- 内部类可以直接访问外部类的私有成员,而不破坏封装。
- 可为外部类,提供必要的内部功能组件
- 实例:
package com.base.demo01;
public class Outer {
private String name;
// 内部类Inner
class Inner {
public void print() {
System.out.println(name); // 直接调用外部类的私有成员
}
}
}
- 编译后:
- 成员内部类
- 在类的内部定义,与实例变量、实例方法同级别的类。
- 外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象。
- 当外部类、内部类存在重名属性时,会优先访问内部类属性。
如要访问外部类属性时,需要用 外部类名.this :Outer.this.name
- 成员内部类 不能定义静态成员,但可以定义静态常量( final )。
- 创建对象:(思路是一样的,只是后者看起来更简洁)
// 调用方式 1:
Outer outer = new Outer();//先创建外部类对象
Inner inner = outer.new Inner();//通过外部类对象建立内部类对象
// 调用方式 2:
Outer.Inner inner = new Outer.new Inner();
- 实例:
package com.base.demo01;
public class Demo01 {
public static void main(String[] args) {
//创建外部类对象
Outer outer = new Outer();
//创建内部类对象
Outer.Inner inner = outer.new Inner();
// 设置外部类属性值
outer.setName("外部 name");
outer.setAge(20);
// 设置内部类属性值
inner.setName("内部 name");
inner.setQq("5435432");
inner.setTel("010");
// 调用内部类的方法
inner.show();
}
}
class Outer { // 外部类
private String name;
private int age;
class Inner { // 内部类
//private static String sex; // 成员内部类中不能定义静态成员
private String name; // 与外部类重名的属性
private String qq;
private String tel;
public void show() {
// 调用外部类中的成员变量
System.out.println("调用外部类成员结果:");
// 重名时,调用外部类属性 (外部类名.this)
System.out.println(Outer.this.name + " " + age);
// 调用内部类中的成员变量
System.out.println("调用内部类成员结果:");
System.out.println(this.name); // this.name 代表当前的内部类
System.out.println(qq + " " + tel);
System.out.println("重名优先调用:");
System.out.println(name); // 重名时,会优先访问内部类属性
}
public void setName(String name) {
this.name = name;
}
public void setQq(String qq) {
this.qq = qq;
}
public void setTel(String tel) {
this.tel = tel;
}
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
- 运行结果:
- 静态内部类
- 不依赖外部类对象(相当于外部类),可直接创建或通过类名访问,可声明静态成员。
- 只能直接访问外部类的静态成员(实例成员需实例化外部类对象)
- 调用外部类属性:通过创建外部类对象调用
// 1. 先创建外部类对象
Outer outer = new Outer();
// 2. 调用外部类对象的属性
System.out.println(outer.name);
- 调用静态内部类的静态属性:直接创建静态内部类对象
Inner.count 通过静态内部类名,直接调用静态内部类的静态属性 - 实例:
package com.base.demo02;
public class Outer {
private String name = "Liu";
static class Inner {
private String tel;
private static int count;
public Inner(String tel, int count) {
this.tel = tel;
// Inner.count 通过静态内部类名,直接调用静态内部类的静态属性
Inner.count = count;
}
public Inner() {
this("",0);
}
public void print() {
// 调用外部类属性
// 1. 先创建外部类对象
Outer outer = new Outer();
// 2. 调用外部类对象的属性
System.out.println(outer.name);
// 调用内部类成员
System.out.println(tel);
// 调用静态内部类的静态属性
System.out.println(count);
}
}
}
- 测试类
package com.base.demo02;
public class Test {
public static void main(String[] args) {
// 直接创建静态内部类对象
Outer.Inner inner = new Outer.Inner("010", 1000);
inner.print();
}
}
- 运行结果:
- 局部内部类(方法中定义内部类)
- 定义在 外部类方法 中,作用范围和创建对象范围仅限于当前方法。不能加任何访问修饰符
- 局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为
final
。 - 限制类的使用范围。
- 实例:
package com.base.demo02;
// 外部类
public class OuterDemo01 {
// 实例变量
private String name = "Liu";
private int age = 30;
// 方法
public void show() {
// 定义局部变量
String address = "北京"; // 默认final 内部类引用
// 局部内部类:注意不能加任何访问修饰符
class Inner {
private String phone = "010";
private String email = "Liu@qq.com";
public void show2() {
// 访问外部类的属性
System.out.println(name); // 相当于 Outer.this.name
System.out.println(age);
// 访问内部类的属性
System.out.println(this.phone); // 内部类属性
System.out.println(this.email);
// 访问局部变量 jdk1.7 要求必须常量 final,jdk1.8 自动添加 final
// 从内部类引用的本地变量必须是最终变量或实际上的最终变量
System.out.println(address);
}
}
// 创建局部内部类对象
Inner inner = new Inner();
inner.show2();
}
}
- 测试类
package com.base;
import com.base.demo02.OuterDemo01;
public class Application {
public static void main(String[] args) {
OuterDemo01 outer = new OuterDemo01();
outer.show();
}
}
- 运行结果:
- 匿名内部类
- 没有类名的局部内部类(一切特征都与局部内部类相同)。
- 必须 继承一个父类 或者 实现一个接口。
- 定义类、实现类、创建对象的语法合并,只能创建一个该类的对象。
- 优点:减少代码量
- 缺点:可读性较差
- 实例:创建接口类
package com.base.demo02;
// 接口
public interface Usb {
void service();
}
- 创建类,实现接口
package com.base.demo02;
public class Mouse implements Usb {
@Override
public void service() {
System.out.println("连接电脑成功,鼠标开始工作...");
}
}
- 测试类
package com.base;
import com.base.demo02.Mouse;
import com.base.demo02.Usb;
public class Application {
public static void main(String[] args) {
// 第一种方式:创建接口类的变量
Usb usb = new Mouse();
usb.service();
// 第二种方式:局部内部类
class Fan implements Usb {
@Override
public void service() {
System.out.println("连接电脑成功,风扇开始工作...");
}
}
Usb usb1 = new Fan();
usb1.service();
// 第三种方式:使用匿名内部类优化(相当于创建了一个局部内部类)
/*
Usb usb2 = new Usb() {
@Override
public void service() {
System.out.println("匿名内部类 连接电脑成功,风扇开始工作...");
}
};
*/
Usb usb2 = () -> System.out.println("匿名内部类 连接电脑成功,风扇开始工作...");
usb2.service();
}
}
- 运行结果:
总结:
- 从上面的案例可以发现:
- 使用内部类的最大好处,在于可以更方便地访问外部类中的私有属性。(优点)
- 使用内部类后代码比之前的更加复杂了,内部类的存在实际上已经破坏了一个类的基本结构。(缺点)
网友评论