1 内部类的基本概念
内部类:所谓内部类就是在一个类的内部进行其他类结构的嵌套的操作
范例:观察内部类的简单定义
class Outer{
private String msg = "Hello World" ;
// ********************************
class Inner{ //定义一个内部类
public void print(){ //定义一个普通方法
System.out.println(msg); //调用msg属性
}
}
// ********************************
//在外部类中定义一个方法,该方法负责产生内部类对象并且调用print()方法
public void fun(){
Inner in = new Inner(); //内部类对象
in.print(); // 内部类提供的print()方法
}
}
public class Test{
public static void main(String[] args) {
Outer out = new Outer(); //外部类对象
out.fun(); //外部类方法
}
}
通过以上代码我们会发现,引入内部类后,程序的结构有些混乱。虽然内部类破坏了程序的结构,但是从另一方面来讲,内部类可以方便的操作外部类的私有访问。
范例:修改上述代码,要求把内部类拆开到外部,主方法代码不变,实现相同的功能。
class Outer{
private String msg = "Hello World" ;
public String getMsg(){ //通过此方法才能取得msg属性
return this.msg ;
}
public void fun(){ //3.现在由out对象调用了fun()方法
Inner in = new Inner(this); //4.this表示当前对象
in.print(); //7.调用方法
}
}
class Inner{
private Outer out;
public Inner(Outer out){ //5.Inner.out = mian.out
this.out = out ; //6.引用传递
}
public void print(){ //8.执行此方法
System.out.println(out.getMsg());
}
}
public class Test{
public static void main(String[] args) {
Outer out = new Outer(); //1. 实例化Outter类对象
out.fun(); //2.调用Outter类方法
}
}
2 内部类为什么存在
1 内部类方法可以访问该类定义所在作用域中的数据,包括被 private 修饰的私有数据。
2. 内部类可以对同一包中的其他类隐藏起来。
3. 内部类可以实现 java 单继承的缺陷。
4. 当我们想要定义一个回调函数却不想写大量代码的时候我们可以选择使用匿名内部类来实现。
范例:使用内部类来实现"多继承"
class A {}
class B {}
class C {
class D extends A {}
class E extends B {}
}
3. 内部类与外部类的关系
- 对于非静态内部类,内部类的创建依赖外部类的实例对象,在没有外部类实例之前是无法创建内部类的
- 内部类是一个相对独立的实体,与外部类不是is-a关系
- 内部类可以直接访问外部类的元素(包含私有域),但是外部类不可以直接访问内部类的元素
- 外部类可以通过内部类引用间接访问内部类元素
范例:内部类可以直接访问外部类的元素
class Outter {
private String outName;
private int outAge;
class Inner {
private int InnerAge;
public Inner() {
Outter.this.outName = "I am Outter class";
Outter.this.outAge = 20;
}
public void display() {
System.out.println(outName);
System.out.println(outAge);
}
}
}
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter().new Inner();
inner.display();
}
}
范例:外部类可以通过内部类引用间接访问内部类元素
class Outter {
public void display() {
// 外部类访问内部类元素,需要通过内部类引用来访问
Inner inner = new Inner();
inner.display();
}
class Inner {
public void display() {
System.out.println("I am InnerClass");
}
}
}
public class Test {
public static void main(String[] args) {
Outter out = new Outter();
out.display();
}
}
4.内部类分类
在Java中内部类主要分为:
- 成员内部类
- 静态内部类
- 方法内部类
- 匿名内部类
4.1 成员内部类 — 类比普通属性/方法
定义:直接定义在外部类之中,不加static修饰符。
在成员内部类中要注意两点:
1.成员内部类中不能存在任何static的变量和方法
2.成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类
在外部类的外部创建成员内部类对象的语法:
外部类.内部类 内部类名称 = new 外部类(). new 内部类();
Outter.Inner in = new Outter(). new Inner();
成员内部类的限制:
成员内部类可以访问外部类的静态属性,成员内部类不能拥有静态域(静态方法和属性都不行)【和内部类关系的第一点矛盾】
4.2 静态内部类 — 类比静态属性/方法
定义:直接定义在外部类中,加static修饰符。
静态内部类只是包在外部类内部而已,除此之外,与普通类没有任何区别,不再需要外部类对象。
在外部类的外部创建静态内部类对象的语法:
外部类.内部类 内部类名称 = new 外部类. 内部类();
Outter.Inner in = new Outter. Inner();
静态内部类的限制:
静态内部类能拥有普通域【它就相当于普通类,只不过套在类中】,但是不能访问外部类的普通域【没有对象】
范例:使用static创建静态内部类
class Outer{
private static String msg = "Hello World" ;
// ********************************
static class Inner{ //定义一个内部类
public void print(){ //此时只能使用外部类中的static操作
System.out.println(msg); //调用msg属性
}
}
// ********************************
//在外部类中定义一个方法,该方法负责产生内部类对象并且调用print()方法
public void fun(){
Inner in = new Inner(); //内部类对象
in.print(); // 内部类提供的print()方法
}
}
public class Test{
public static void main(String[] args) {
Outer.Inner in = new Outer.Inner();
in.print();
}
}
4.3 方法内部类—类比于方法中的一个局部变量
方法内部类定义在外部类的方法中,局部内部类和成员内部类基本一致,只是它们的作用域不同,方法内部类只能在该方法中被使用,出了该方法就会失效。 对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类。
- 局部内类不允许使用访问权限修饰符 public private protected 均不允许
- 局部内部类对外完全隐藏,除了创建这个类的方法可以访问它其他的地方是不允许访问的。
- 局部内部类要想使用方法形参,该形参必须用final声明(JDK8形参变为隐式final声明).
范例:使用方法内部类
class Outter {
private int num;
public void display(int test) {
class Inner {
private void fun() {
num++;
System.out.println(num);
System.out.println(test);
}
}
new Inner().fun();
}
}
public class Test {
public static void main(String[] args) {
Outter out = new Outter();
out.display(20);
}
}
4.4 匿名内部类
匿名内部类其实就是一个没有名字的方法内部类,所以它符合方法内部类的所有约束。除此之外,还有一些地方需要注意:
- 匿名内部类是没有访问修饰符的。
- 匿名内部类必须继承一个抽象类或者实现一个接口。
- 匿名内部类中不能存在任何静态成员或方法。
- 匿名内部类是没有构造方法的,因为它没有类名。
- 与局部内部相同匿名内部类也可以引用方法形参。此形参也必须声明为 final
范例: 使用匿名内部类
interface MyInterface {
void test();
}
class Outter {
private int num;
public void display(int para) {
// 匿名内部类,实现了MyInterface接口
new MyInterface(){
@Override
public void test() {
System.out.println("匿名内部类"+para);
}
}.test();
}
}
public class Test {
public static void main(String[] args) {
Outter outter = new Outter();
outter.display(20);
}
}