【JAVA入门】Day16 - 内部类

【JAVA入门】Day16 - 内部类



        类的五大成员:属性、方法、构造方法、代码块、内部类。

        内部类,顾名思义,就是在一个类的里面,再定义一个类。
        如下:在 A类 的内部定义 B类,B类 就被称为内部类。

public class Outer {	//外部类
	public class Inner {	//内部类
	
	}
}
public class Test {			//外部其他类
	public static void main(String[] args) {
	
	}
}

一、为什么要有内部类

        举个例子。
        需求:写一个 Javabean 类描述汽车。
        属性:汽车的品牌、年龄、颜色、发动机的品牌、发动机使用年限。
        这个例子下,发动机有自己的品牌和使用年限,它和汽车是不同的个体,但是又依赖于车,离开了车,发动机也没有意义。此时我们称之为依赖的同时又保持自身的部分独立性。这个时候,我们就可以使用内部类,把发动机定义为一个内部类。

public class Car {	//外部类
    String carName;
    int carAge;
    int carColor;

    class Engine {	//内部类
        String engineName;
        int engineAge;
    }
}
  • 内部类表示的事物是外部类的一部分。
  • 内部类单独出现没有任何意义。
  • 内部类可以直接访问外部类的成员,包括私有成员。
  • 外部类要访问内部类的成员,必须创建对象。

二、内部类的分类

        内部类主要有四种:

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类

2.1 成员内部类

        写在成员位置的,属于外部类的成员

public class Car {	//外部类
    String carName;
    int carAge;
    int carColor;

    class Engine {	//成员内部类
        String engineName;
        int engineAge;
    }
}
2.1.1 成员内部类可以被权限修饰符修饰

        成员内部类也是可以被一些修饰符所修饰的,比如:private,默认,protected,public,static 等。

public class Car {	//外部类
    String carName;
    int carAge;
    int carColor;

    private class Engine {	//成员内部类
        String engineName;
        int engineAge;
    }
}
2.1.2 如何获取成员内部类的对象

        如果想获取成员内部类的对象,有两种方式:

  • 在外部类中编写方法,对外提供内部类的对象。
  • 直接创建格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
    范例:Outer.Inner oi = new Outer().new Inner();

        由于内部类可以用 private 修饰,此时内部类将会变成私有的,那么就不能在外界随意创建他的对象,即Outer.Inner oi = new Outer().new Inner(); 会报错,因此第一种调用方法就出现了,可以利用外部类编写方法,对外提供内部类的对象。

public class Outer {
	String name;

	private class Inner {
	
	}

	//获取一个内部类对象
	public Inner getInstance() {
		return new Inner();
	}
	
}
public class Test {
    public static void main(String[] args) {
        Outer o = new Outer();
        //Outer.Inner oi = new Outer().new Inner();报错
        //因为 Inner 私有,所以不能直接写 Outer.Inner
        //可以利用Object类声明接受(Object是所有类的公有父类)
        //这里是一种多态(Object是Inner的父类,子类对象赋值给父类,是为多态)
        Object ob = o.getInstance();
        System.out.println(ob);// InnerClass.Outer$Inner@2133c8f8
    }
}

        如果内部类不用 private 修饰,而是默认或用 public 修饰,那么内部类就可以直接在外界被访问,此时可以使用第二种调用方法。

public class Outer {
	private String name;

	public class Inner {
	
	}
}
public class Test {
    public static void main(String[] args) {
        Outer o = new Outer();
        Outer.Inner oi = new Outer().new Inner();
        System.out.println(oi);// InnerClass.Outer$Inner@2133c8f8
    }
}
2.1.3 JDK16 后新增的成员内部类里可以定义静态变量

        在成员内部类里,JDK16 之前不能定义静态变量,JDK16 开始才可以定义静态变量。

public class Inner {
	static int a = 10;
}
2.1.4 成员内部类如何获取外部类的成员变量

        成员内部类获取外部类成员变量,复杂的是重名的情况(如果不重名,各写各的名字即可),这个时候仍采取的是就近原则。

class Outer {
	private int a = 10;
	class Inner {
		private int a = 20;
		public void show() {
			int a = 30;
			System.out.println(Outer.this.a);	//10
			System.out.println(this.a); //20
			System.out.println(a); //30
		}
	}
}

2.2 静态内部类

        静态内部类就是用 static 修饰的内部类。

public class Car {	//外部类
    String carName;
    int carAge;
    int carColor;

    static class Engine {	//静态内部类
        String engineName;
        int engineAge;
    }
}

        静态内部类只能访问外部类中的静态变量静态方法,如果想要访问非静态的需要创建对象
        创建静态内部类对象的格式:

外部类名.内部类名 对象名 = new 外部类名.内部类名();

        静态内部类调用非静态方法的格式:

先创建对象,用对象调用。

        静态内部类调用静态方法的格式:

外部类名.内部类名.方法名();

        如下代码所示,show1() 是非静态方法,show2() 是静态方法。
        要想在内部类中访问外部类的静态变量,直接调用访问即可;但要想访问外部类种的非静态方法,就要先创建一个外部类的对象,再用对象调用这个非静态变量。

public class Outer {
	int a = 10;
	static int b = 20;
    //静态内部类
    static class Inner {

        public void show1() {
         	Outer o = new Outer();
            System.out.println(o.a);
            System.out.println(b);
            System.out.println("内部类的非静态方法被调用了");
        }
        public static void show2() {
         	Outer o = new Outer();
            System.out.println(o.a);
            System.out.println(b);
            System.out.println("内部类的静态方法被调用了");
        }
    }
}

        在测试类当中,如果想要访问静态内部类中的静态方法 show2(),直接用类名点上方法即可(只要是静态的东西,都可以直接用类名获取);但是如果想访问静态内部类中的非静态方法 show1(),需要先创建这个内部类的对象,再用对象调用 show1()。

public class Test {
    public static void main(String[] args) {
        Outer.Inner oi = new Outer.Inner();
        oi.show1();
        Outer.Inner.show2();
    }
}

        由此可知,凡是静态相关的东西,都是用类名直接调用;凡是非静态的东西,都是用对象调用。

3.1 局部内部类

        1.将内部类定义在方法里面,就叫局部内部类,类似于方法里的局部变量
        2.外界无法使用局部内部类,需要在方法内部创建对象并使用。
        3.该类可以直接访问外部类的成员,也可以访问方法内的局部变量。

public class Outer {
   int b = 20;

    public void show() {

        int a = 10;

        //局部内部类
        class Inner{
            String name;
            int age;

            public void method1(){
                System.out.println(a);
                System.out.println(b);
                System.out.println("局部内部类中的method1方法");
            }

            public static void method2(){
                System.out.println("局部内部类中的method2方法");
            }

        }

        //创建局部内部类的对象
        Inner i = new Inner();
        System.out.println(i.name);
        System.out.println(i.age);
        i.method1();
        Inner.method2();

    }
}
public class Test {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.show();
    }
}

3.2 匿名内部类

        匿名内部类本质上是隐藏了名字的内部类。
        匿名内部类既可以作为成员内部类,也可以作为局部内部类存在。

        格式:

new 类名或接口名() {
	重写方法;
};

        举例:

new Inter() {
	public void show() {
	}
};

        new Inter 后面的 { },实质上是类的内容,是一个类,这个类本身是没有名字的,所以叫匿名内部类,而这个类实现了 Inter 这个接口,因此需要在其内部重写接口里所有的抽象方法。而 new 就是创建了这个没有名字的类的对象。

        举例2:

public abstract class Animal {
    public abstract void eat();
}
public class Test {
    public static void main(String[] args) {

        new Animal() {
          @Override
          public void eat() {
              System.out.println("重写了eat方法");
          }
          
        };
    }
}

        此时的匿名内部类起到的作用是继承,继承的是前面的 Animal 类,并对 Animal 里的所有抽象方法进行了实现。
        匿名内部类的诞生其实也是为了简化代码,将一次实现/继承生成的对象作为参数,传递给某个方法,大大减少了代码量,优化了很多步骤。

public class Test {
    public static void main(String[] args) {
			method(
 				new Animal() {
          			@Override
          			public void eat() {
              			System.out.println("重写了eat方法");
          			}
        		}
        	);  //用一个匿名内部类生成的对象作为参数传递给method方法
    }
    
    public static void method(Animal a) {	//将匿名内部类传递给a,在匿名内部类中重写eat方法,实现了一个多态
    	a.eat();
    }
}

        匿名内部类生成的对象,也可以采用链式编程,调用自己内部的所有方法:

new Swim() {

	@Override
	public void swim() {
		System.out.println("重写游泳方法");
	}
	
}.swim();

        匿名内部类还可以实现接口的多态:

//接口多态
Swim s = new Swim(){   //接口创建的对象被匿名内部类实现了
	@Override
	public void swim() {
		System.out.println("重写的游泳方法");
	}
};

s.swim();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值