面向对象(17):内部类及其案例

面向对象(17):内部类及其案例

一、内部类的介绍

1、内部类的概述

把类定义在其他类的内部,我们称之为内部类
举例:在类A中定义了一个类B,类B就是内部类

2、内部类的特点

(1)内部类可以访问外部类的成员,包括私有和静态的外部类成员
(内部类如果是静态的,就不能访问外部类私有的,但是可以访问静态的成员)

案例:
class Outer{
    private int num = 10;

    class Inner{
        public void show(){
            System.out.println(num);
        }
    }
}

(2)外部类要想访问内部类的成员,就必须要创建内部类的对象

案例:
class Outer{
    private int num = 10;

    class Inner{
        public void show(){
            System.out.println(num);
        }
    }
//在外部类中创建一个方法,在方法中创建内部类对象,通过内部类对象来访问内部类成员
    public void show2(){
        //创建内部类对象
        Inner inner = new Inner();
        inner.show();
    }
}

3、内部类位置

根据内部类定义的位置不同,可以分为两种类型:
(1)成员的位置上(成员内部类)
(2)局部的位置上(局部内部类),定义在方法内的

案例:
class Outer2{

    //成员内部类
    class Inner2{
    }
    
    public void fun(){
        //局部内部类
        class Inner3{
        }
    }
}

4、成员内部类的修饰符

成员内部类常见的修饰符为:private、static
            private:为了保证数据安全性
            static:为了方便访问数据
静态修饰的特点:
    内部类如果是静态修饰的,只能访问外部类静态的成员

案例:

class Outer4{
    private int num = 10;
    private static int num2 = 30;

    static class Inner4{
        public static void show2(){
	//System.out.println(num);静态的内部类不能访问外部私有的,会报错
            System.out.println(num2)//静态的内部类可以访问外部类静态的成员
        }
    }

二、成员内部类

1、如果内部类是非静态的,在测试类中该如何访问内部类中的成员?

格式(1)外部类名.内部类名 对象名 = new 外部类名().new 内部类名();
			     = 外部类对象.内部类对象;
	(2)通过对象名调取

2、如果内部类是静态的,在测试类中如何访问内部类中的成员呢?

如果内部类是静态的,内部类成员是非静态的 ,测试类中需要创建对象来调取内部类成员

	外部类名.内部类名 对象名 = new 外部类类名.内部类类名();
			对象名.成员名;//调取静态内部类的非静态成员变量
			对象名.成员名();//调取静态内部类的非静态成员方法

如果内部类是静态的,内部类成员也是静态的 ,测试类中可以通过类名直接调用内部类成员

	外部类名.内部类名.成员名;//调取静态内部类的静态成员变量
	外部类名.内部类名.成员名();//调取静态内部类的静态成员方法

3、案例:

class Outer {
   public int num = 10;
   class Inner {
      public int num = 20;
      public void show() {
         int num = 30;
         System.out.println(?);
         System.out.println(??);
         System.out.println(???);
      }
   }
}

		需求:在控制分别输出:30,20,10

答:

//外部类
class Outer5 {
    public int num = 10;
    //内部类
  class Inner5 {
      //成员内部类
      public int num = 20;
      public void show() {
         int num = 30;
         System.out.println(num);//这里的num代表方法里的局部变量30
            
         System.out.println(this.num);//this表示这里的num代表当前类的成员变量 
         
            //Inner5与Outer5不是继承关系,不能使用super关键字
			//System.out.println(super.num);
			
            System.out.println(Outer5.this.num);//表示当前外部类下的成员变量10
   //或者 System.out.println(new Outer5().num);通过外部类对象调取外部类成员变量 
        }
    }
}

public class InnerClassDemo5 {
    public static void main(String[] args) {
    	//内部类是非静态的,成员也非静态的
        Outer5.Inner5 oi5 = new Outer5().new Inner5();
        oi5.show();
    }
}
            执行结果如下:
                    30
                    20
                    10

                    Process finished with exit code 0

三、局部内部类

1、位置:定义在方法内的类称之为局部内部类

2、局部内部类的特点

特点(1)可以直接访问外部类的所有成员

案例:
class Outer6{
    private int num = 10;

    public void fun(){
        int num2 = 100;
        //局部内部类
        class Inner6{
            int num3 = 200;
            //局部内部类中的方法
            public void show(){
        		System.out.println(num);//外部类的成员变量
       			System.out.println(num2);//外部类方法中的成员变量
       		 	System.out.println(num3);//局部内部类中的成员变量
            }
        }

如果想要实现上面局部内部类的show方法,该怎么办?

①需要在外部类成员方法内、局部内部类外,创建局部类对象

②在测试类中中创建外部类对象,调取外部类成员方法

class Outer6{
    private int num = 10;
	//外部类的成员方法
    public void fun(){
        int num2 = 100;
        //局部内部类
        class Inner6{
            int num3 = 200;
            //局部内部类中的方法
            public void show(){
        		System.out.println(num);//外部类的成员变量
       			System.out.println(num2);//外部类方法中的成员变量
       		 	System.out.println(num3);//局部内部类中的成员变量
           }
        }
        //需要在外部类的成员方法中创建内部类对象
        Inner6  inner6 = new Inner6();
        //调取内部类的show方法
        inner6.show();
      }
    }
    
//测试类
public class InnerClassDemo6 {
    public static void main(String[] args) {
    	//创建外部类对象
        Outer6 outer6 = new Outer6();
        //调取外部类成员方法
        outer6.fun();
    }
}
            执行结果如下:
             		10
                        100
                        200

                        Process finished with exit code 0

由上得出局部内部类的第二个特点:

特点(2)可以在外部类中的局部范围中创建对象,通过对象调用内部类中的方法,来使用内部类的局部功能

3、局部内部类访问局部变量的注意事项

通过反编译工具查看后发现, 局部内部类存在的方法中定义的局部变量自动加上了final,不能进行二次赋值
特点:jdk1.8之后会自动添加final关键字

四、匿名内部类

1、匿名内部类的含义

匿名内部类是内部类的一个简化写法

2、存在匿名内部类的前提

要存在一个类或者是一个接口,类可以是具体的类也可以是抽象类

3、定义格式

new 类名或者接口名(){重写方法;}
本质上:
    是一个继承了这个类或者实现了这个接口的子类匿名对象

案例:

/创建一个接口
interface  Inner{
    //定义两个抽象方法
    public abstract void show1();
    public abstract void show2();
}

class Outer{
    //创建一个方法
    public void fun(){
    //匿名内部类
        new Inner(){
            //重写方法
            @Override
            public void show1() {
                System.out.println("这是show1方法");
            }

            @Override
            public void show2() {
                System.out.println("这是show2方法");
            }
        }.show1();//new Inner(){}整体相对于new了一个接口的对象
                    //可以直接调用接口中的方法
    }
}

public class InnerClassDEmo11 {
    public static void main(String[] args) {
        //想要调用fun方法,必须先创建外部类对象
        Outer outer = new Outer();
        outer.fun();
    }
}
        执行结果如下:
                    这是show1方法

                    Process finished with exit code 0
//如果想要再调取show2方法,必须再创建一个匿名内部类,因为匿名对象只能使用一次

想一想,如果接口中的方法很多的时候,每次调用一个方法,都需要new一下,要写的内容都重复
了,怎么改进?

使用多态的形式,这里叫做接口多态,将匿名内部类用接口来接收一下

/创建一个接口
interface  Inner{
    //定义两个抽象方法
    public abstract void show1();
    public abstract void show2();
}

class Outer{
    //创建一个方法
    public void fun(){
    //接口多态:用接口来接收一下匿名内部类
        Inter i = new Inner(){
            //重写方法
            @Override
            public void show1() {
                System.out.println("这是show1方法");
            }

            @Override
            public void show2() {
                System.out.println("这是show2方法");
            }
        };
        i.show1();//在fun方法中直接调取show1()
        i.show2();//在fun方法中直接调取show2()
    }
}

public class InnerClassDEmo11 {
    public static void main(String[] args) {
        //想要调用fun方法,必须先创建外部类对象
        Outer outer = new Outer();
        outer.fun();
    }
}
        执行结果如下:
                    这是show1方法
                    这是show2方法

                    Process finished with exit code 0

学习了匿名内部类,接口的写法又多了一个

之前:
	//接口
    interface A{
                b();
                c();
              }
              
	//创建一个类来实现接口
    class B implements A{
            b(){..}//重写方法
            c(){..}//重写方法
            }
            
	//在测试类中使用接口多态创建对象
        A a = new B();
    
现在:
    //接口
    interface A{
                b();
                c();
              }

     //在外部类中的一个方法内
     A a = new A(){
             	b(){..}//重写方法
                c(){..}//重写方法
            };

     //测试类中
   创建外部类对象,然后调取外部类的方法,就相当于实现了接口

五、匿名内部类在开发中的使用案例

实现接口的方法一:接口传参

//在开发中,会有人提供一个接口给我们
interface Person{
    public abstract void study();
}

//定义一个类
class PersonDemo{
    //创建一个方法,接口作为形参传入进去
    //当接口作为方法的参数的时候,实际上需要的是实现该接口类的对象
    public void fun(Person p){
        p.study();
    }
}

//定义一个类,来实现该接口
//当接口作为方法的参数的时候,需要的就是本类的对象
class Student66 implements Person{

    @Override
    public void study() {
        System.out.println("好好学习");
    }
}

//测试类
public class InnerClassDemo1 {
    public static void main(String[] args) {
        //想要调方法,先创建对象
        PersonDemo pd = new PersonDemo();
        Student66 s = new Student66();
        pd.fun(s);
    }
}

实现接口的方法二(高级):接口传参、使用匿名对象

//在开发中,会有人提供一个接口给我们
interface Person{
    public abstract void study();
}

//定义一个类
class PersonDemo{
    //创建一个方法,接口作为形参传入进去
    //当接口作为方法的参数的时候,实际上需要的是实现该接口类的对象
    public void fun(Person p){
        p.study();
    }
}

//定义一个类,来实现该接口
//当接口作为方法的参数的时候,需要的就是本类的对象
class Student66 implements Person{

    @Override
    public void study() {
        System.out.println("好好学习");
    }
}

//测试类
public class InnerClassDemo1 {
    public static void main(String[] args) {
        //想要调方法,先创建对象
        PersonDemo pd = new PersonDemo();
//        Student66 s = new Student66();
        pd.fun(new Student66());
    }
}

实现接口的方法三(更高级1):使用匿名内部类

不需要专门写一个类来实现接口

//在开发中,会有人提供一个接口给我们
interface Person{
    public abstract void study();
}

//定义一个类
class PersonDemo{
    //创建一个方法,接口作为形参传入进去
    //当接口作为方法的参数的时候,实际上需要的是实现该接口类的对象
    public void fun(Person p){
        p.study();
    }
}

//测试类
public class InnerClassDemo1 {
    public static void main(String[] args) {
        //想要调方法,先创建对象
        PersonDemo pd = new PersonDemo();
        pd.fun(new Person() {	//直接调取fun方法,将匿名内部类当参数传入进去
            @Override
            public void study() {
                System.out.println("好好学习");
            }
        });
    }
}

实现接口的方法三(更高级2):使用构造方法

//在开发中,会有人提供一个接口给我们
interface Person{
    public abstract void study();
}

//定义一个类
class PersonDemo{
    Person p;
    //构造方法
    PersonDemo(Person p){
    this.p = p;
    }
}


//测试类
public class InnerClassDemo1 {
    public static void main(String[] args) {
     //使用匿名内部类的形式创建对象,并将匿名内部类当参数传入进去
        PersonDemo pd = new PersonDemo(new Person() {
            @Override
            public void study() {
                System.out.println("好好学习");
            }
        });

        Person p = pd.p; //pd.p.var回车
        p.study();
        /*
          或者
                PersonDemo pd = new PersonDemo(new Person() {
                @Override
                public void study() {
                    System.out.println("好好学习");
                }
            }).p.study();
         */
    }
}

六、匿名内部类面试题

/*
    interface Inter { void show(); }
	class Outer { //补齐代码 }
	class OuterDemo {
	    public static void main(String[] args) {
		      Outer.method().show();
		  }
	}
要求在控制台输出”HelloWorld”
分析:
    1、method()方法可以通过类名直接调用➡说明method()方法是静态的
    2、调用完method()方法之后又可以去 .show() 方法,而show()方法恰好是接口Inter中的方法
        ➡说明method()方法是有返回值的,而且返回值类型是Inter类型
*/

interface Inter2 {
    void show();
}

class Outer8 {
    //1、推出第一个结论:method方法是静态的

    //2、推出第二个结论:由于main方法中调用完method方法之后还能继续调用方法
    //所以得出method方法是有返回值的,由于show方法恰好是接口Inter2中的方法,所以返回值类型
    //是接口Inter2类型
    public static Inter2 method(){

        //使用匿名内部类的形式
        return new Inter2() {
            @Override
            public void show() {
                System.out.println("HelloWorld");
            }
        };
    }
}

public class InnerClassDemo9 {
    public static void main(String[] args) {
        Outer8.method().show();
    }
}
posted @ 2021-12-15 21:51  阿伟宝座  阅读(205)  评论(0)    收藏  举报