day13 Java 内部类 匿名内部类


它名叫阿福,整天跟着我
在我最最难过的时候




一、内部类

1、基础

把类定义在其他类的内部,这个类就被称为内部类

class Outer{
    
    
	class Inner{
    
    
	}
}

2、特点

1、内部类可以直接访问外部类的成员,包括私有
2、外部类要访问内部类的成员,必须创建对象(要在方法内创建,否则是成员变量)

class Outer {
    
    
    private int num = 20;
    
    class Inner {
    
    
        int num2 = 200;
        public void show() {
    
    
        	//直接访问外部类私有成员
            System.out.println(num);
        }
    }

    public void show2(){
    
    
    	//创建内部类对象,调用内部类成员
        Inner inner = new Inner();
        System.out.println(inner.num2);
        inner.show();
//        System.out.println(num2);
    }


}

3、成员内部类

按照内部类在类中定义的位置不同,可以分为如下两种格式:
1、成员位置(成员内部类)
2、局部位置(局部内部类)

class Outer2{
    
    
    //定义在成员位置,叫做成员内部类
    class Inner{
    
    }

    public void show(){
    
    
        //定义在局部位置,叫做局部内部类
        class Inner2{
    
    }
    }
}

4、外部调用内部类

同样需要依靠创建内部类对象
1、普通内部类
外部类名.内部类名 对象名 = 外部类对象.内部类对象;

Outer.Inner oi = new Outer().new Inner();

2、静态内部类
外部类名.内部类名 对象名 = new 外部类名.内部对象
此时内部类属性的静态,通过外部类名直接调用内部类构造方法

Outer.Inner oi = new Outer.Inner();

5、内部类常见修饰符

1、private 为了保证数据的安全性
2、static 为了让数据访问更方便

private 修饰的内部类只能在外部类中调用,无法在外部创建实例

//private 内部类
class Body{
    
    
    private class Heart{
    
    
        public void bloodXunHuan(){
    
    
            System.out.println("提供血液循环");
        }
    }
    public Heart show(){
    
    
    	私有的在类内部都可以随意访问,所以此处可以创建他的对象
        Heart heart = new Heart();
        heart.bloodXunHuan();
        return heart;
        //利用返回值,试图在外部拿到这个private类(实际上也是不行)
    }
}

static 修饰的内部类需要注意外部创建对象的格式,并且调用内部类方法更加方便

//static 内部类
class Body{
    
    
    public static class Heart{
    
    
        public static void bloodXunHuan(){
    
    
            System.out.println("提供血液循环");
        }
    }
    public void show(){
    
    
        Heart heart = new Heart();
        heart.bloodXunHuan();
    }
}
public class InnerClassDemo4 {
    
    
    public static void main(String[] args) {
    
    
        //当内部类被静态修饰后,访问的格式就变了:
        //外部类名.内部类名 对象名 = new 外部类名.内部对象
        Body.Heart bh = new Body.Heart();
        bh.bloodXunHuan();
        
        //调用bloodXunHuan()另一种方式  链式编程
        new Body.Heart().bloodXunHuan();
        //当方法也是static时,可以不经过对象,直接通过内部类名调用方法
        Body.Heart.bloodXunHuan();

6、练习

/*
在控制分别输出:30,20,10
      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(???);
			}
		}
	}
	    注意:内部类与外部类没有继承关系
 */
 class Outer {
    
    
    public int num = 10;
    class Inner {
    
    
        public int num = 20;
        public void show() {
    
    
            int num = 30;
            System.out.println(num);
            //指向当前内部类对象
            System.out.println(this.num);
            //第一种方式,创建外部类对象,访问成员变量
            System.out.println(new Outer().num);
            //第二种方式,理解为 this Outer 的 num 更好理解
            System.out.println(Outer.this.num);
        }
    }

7、局部内部类

1、可以直接访问外部类的成员
2、可以方法内创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能

class Outer {
    
    
    private int num = 10;
    public void show(){
    
    
        int num2 = 100;
        
        class Inner{
    
    
            int num3 = 200;
            public void show(){
    
    
//                num2 = 400; 
//                不可以,jdk1.8之后会自动在局部方法上的局部变量添加final
                System.out.println(num3);
            }
        }
        num2 = 500;
        System.out.println(num2);

        Inner inner = new Inner();
        inner.show();
    }
//        不可以
//        Inner i = new Inner();
}

二、匿名内部类

匿名内部类:
就是内部类的简化写法。

前提:
存在一个类或者接口
这里的类可以是具体类也可以是抽象类。

格式:

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

1、例一

interface Inner{
    
    
    public abstract void show();
    public abstract void show2();
}

class Outer{
    
    
    public void fun(){
    
    
		//匿名内部类调用方法show
        new Inner(){
    
    
            @Override
            public void show() {
    
    
                System.out.println("show");
            }
            @Override
            public void show2() {
    
    
                System.out.println("show2");
            }
        }.show();
		//匿名内部类调用方法show2
        new Inter(){
    
    
            @Override
            public void show() {
    
    
                System.out.println("show");
            }
            @Override
            public void show2() {
    
    
                System.out.println("show2");
            }
        }.show2();
        //问题:如果我这个接口有很多方法,还要使用匿名内部类的形式就很麻烦
        //因为每次调用里面实现的方法,多需要创建一个内部类,怎么改进?
        System.out.println("====改进版=======");
        Inter i = new Inter(){
    
     //多态
            @Override
            public void show() {
    
    
                System.out.println("show");
            }
            @Override
            public void show2() {
    
    
                System.out.println("show2");
            }
        };
        i.show();
        i.show2();
        System.out.println("============");
    }
}

public class InnerClassDemo {
    
    
    public static void main(String[] args) {
    
    
        Outer o = new Outer();
        outer.fun();
    }
}

2、例二

interface Person8{
    
    
    public abstract void study();
}

class PersonDemo8{
    
    
    //当接口做为参数传递的时候,实际上需要的是该接口实现类的对象
    public void fun(Person8 person8){
    
    
        person8.study();
    }
}

public class InnerClassDemo8 {
    
    
    public static void main(String[] args) {
    
    
        PersonDemo8 p = new PersonDemo8();
        System.out.println("使用匿名内部类实现=====");

        personDemo8.fun(new Person8(){
    
    
            @Override
            public void study() {
    
    
                System.out.println("这是使用匿名内部类的方式实现");
            }
        });              
        //至此全为该方法的形参及其描述
    }
}

3、例三

/*
    interface Inter { void show(); }
	class Outer { //补齐代码 }
	class OuterDemo {
	    public static void main(String[] args) {
		      Outer.method().show();
		  }
	}
    要求在控制台输出”HelloWorld”

      通过观察main方法的实现发现,可以直接通过类名.方法的形式
      说明method方法是静态的
      又因为调用完method方法之后还可以调用方法,说明method方法的返回值是一个对象
      又因为,后面调的方法是show()方法,通过观察发现,是接口Inter中的show()方法
      所以大胆判断,method方法的返回值是接口Inter
 */
 
interface Inter {
    
    
    public abstract void show();
}

class Outer {
    
    
//	由于返回值类型是一个接口类型,所以需要的是该接口实现类的对象
    public static Inter method(){
    
    
//        在还没有学习匿名内部类之前,可以创建demo类实现该接口,再调用
//        Demo9 demo = new Demo();
//        return demo;

//        学习匿名内部类之后
        return new Inter9(){
    
    
            @Override
            public void show() {
    
    
                System.out.println("HelloWorld");
            }
        };
    }
}



总结

内部类
1、内部类可以直接访问外部类的成员,包括私有
2、外部类要访问内部类的成员,必须创建对象(要在方法内创建,否则是成员变量)

1、普通内部类
外部类名.内部类名 对象名 = 外部类对象.内部类对象;

Outer.Inner oi = new Outer().new Inner();

2、静态内部类
外部类名.内部类名 对象名 = new 外部类名.内部对象
此时内部类属性的静态,通过外部类名直接调用内部类构造方法

Outer.Inner oi = new Outer.Inner();

匿名内部类
格式:

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

Guess you like

Origin blog.csdn.net/qq_41464008/article/details/120627663