文章目录

  • 1.内部类
  • 2.成员内部类
  • 3.局部内部类
  • 4.静态内部类
  • 5.匿名内部类
  • 5.1.成员匿名内部类
  • 5.2.局部匿名内部类


1.内部类

书写在外部类中的类,称之为内部类。

根据内部类在外部类中书写的位置,又分为:

①成员内部类
②局部内部类
③静态内部类
④匿名内部类

2.成员内部类

与外部类的成员属性和成员方法平级的类。

  • 语法:
访问权限修饰符 class 外部类类名{
            //外部类的属性和方法
            //成员内部类
            访问权限修饰符 class 内部类类名{
               //属性和方法
            }      
      }

案例:

1、与外部类的属性和方法平级。

public class Outer {

	private int num;

	public void show() {
		System.out.println("外部类的属性值num=" + num);
	}

	/**
	 * 成员内部类
     * 与外部类的属性和方法平级。
	 */
	public class Inner {
	
		private int score;

		public void display() {
			//内部类可以访问外部类的属性和方案
			System.out.println("外部类的属性num = " + num);
			show();
			System.out.println("内部类的属性score = " + score);
		}

	}
}

2、外部类的属性和方法属于对象,所以,与之类似,成员内部类属于外部类对象。据此,推导出:成员内部类对象的构建方式

外部类.内部类 实例名 = 外部类对象.new 内部类的构造方法
/**
 * 成员内部类的演示
 */
public class MemberInnerClassDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // 如何构建成员内部类对象

        // 1、访问外部类的方法
        Outer outer = new Outer();
        outer.show();

        // 2、访问内部类的方法
        // ①构建成员内部类对象
        Outer.Inner inner = outer.new Inner();

        // ②调用方法
        inner.display();
    }
}

3、如何在成员内部类方法中访问同名的变量(外部类的属性、内部类的属性,内部类方法中的局部变量)

public class Outer2 {
    private int num = 4;

    /**
     * 成员内部类
     */
    public class Inner {

        private int num = 3;

        public void display() {
            int num = 5;
            // 明确指定this指的是外部类当前对象的一个引用;若不写出来,默认是当前类对象的一个引用
            System.out.println("外部类的属性num = " + Outer2.this.num);
            System.out.println("内部类的属性num = " + this.num);
            System.out.println("内部类方法display()中的局部变量num = " + num);
        }
    }
}
外部类的属性--》  访问方式:外部类类名.this.属性
内部类的属性--》  访问方式:this.属性
内部类方法中的局部变量--》访问方式:局部变量名

4、成员内部类可以使用private,default,protected,public等等访问权限修饰符来修饰。
5、包含了成员内部类的源码,编译时会生成的字节码文件的个数与class的个数相同

注意:成员内部类生成的字节码文件的名字:外部类类名JavaSE面向对象(九)-内部类_javaInner.class

3.局部内部类

与外部类中成员方法中的局部变量平级的内部类。

语法:

访问权限修饰符 class 外部类类名{
            //外部类的属性
           访问权限修饰符 返回值类型 方法名(形式参数列表){
               
	            //局部变量
	
	           	//局部内部类不能使用权限修饰符
	           	class 内部类类名{
	             	 //属性和方法
	           	} 
    	 }	     
      }

案例:
特点:
1、与外部类方法体中的局部变量同一个级别,且使用方式类似。

public class Outer {
    private int num = 4;

    /**
     * show
     */
    public void show() {

		int score = 67;

        // 局部内部类
        class Inner {
            private int x;
            /**
             * 内部类中的方法
             */
            public void display() {
                System.out.println("外部类中的属性num = " + num);
                //局部内部类访问与之平级的局部变量,该局部变量必须是局部常量此常量仅限于JDK1.7之前 JDK1.8无需添加final
                System.out.println("与内部类平级的局部变量score = " + score);
                System.out.println("局部内部类中的属性x = " + x);
            }

        }

		/*
			如何构建局部内部类的对象?
		   与局部变量类似,局部变量的使用范围仅限于其所在的方法体或者代码块
			同理,局部内部类只能在其所在的方法体中构建对象。
			  --》如何调用局部内部类中的方法
		   不能直接调用,只能间接调用(调用局部内部类所在的方法)跳转到测试类中进行验证
		*/
        Inner inner = new Inner();
        inner.display();
    }

}

测试类:

public class LocalInnerClassGrammarDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Outer outer = new Outer();
		outer.show();
	}
}

2、局部内部类中如何访问同名变量

public class Outer2 {
	private int num = 4;


	public void show() {
		int num2 = 67;

		// 局部内部类
		class Inner {
			private int num = 5;

			/**
			 * 内部类中的方法
			 */
			public void display() {
				int num = 1;
				System.out.println("外部类中的属性num = " + Outer2.this.num);
				System.out.println("与局部内部类平级的局部变量num2 = " + num2);//只有一种解决方案,改名字
				System.out.println("局部内部类中的属性num = " + this.num);
				System.out.println("局部内部类中方法display()中的局部变量num = " + num);
			}

		}
		// 构建局部内部类对象
		Inner inner = new Inner();
		inner.display();
	}
}

3、局部内部类访问与之平级的局部变量,该局部变量必须是局部常量
4、如何构建局部内部类的对象?

与局部变量类似,局部变量的使用范围仅限于其所在的方法体或者代码块同理,局部内部类只能在其所在的方法体中构建对象。

5、如何调用局部内部类中的方法

不能直接调用,只能间接调用(调用局部内部类所在的方法)

6、包含了局部内部类的外部类,编译时,有几个class就会生成几个字节码文件

注意:局部内部类的字节码文件名是:外部类类名.序号+内部类类名.class 如:Outer.1Inner.class

4.静态内部类

与外部类的静态属性和静态方法平级的内部类。

语法:

访问权限修饰符 class 外部类类名{
            //外部类的属性和方法

            //外部类的静态属性和静态方法

            //静态内部类
            访问权限修饰符 static class 内部类类名{
               //属性和方法
            }      
      }

案例:

public class Outer {
    private int num = 3;

    private static String name = "独孤求败";

    public void show() {
        System.out.println("外部类普通方法show()....");
    }

    public static void display() {
        System.out.println("外部类静态方法display()....");
    }

    // 静态内部类
    static class Inner {
        int score = 45;

        /**
         * 普通方法
         */
        public void doSomething() {
            System.out.println("静态内部类中的普通方法doSomething()。。。");

        }
        /**
         * 静态方法
         */
        public static void invoke() {
            System.out.println("静态内部类中的静态方法invoke()。。。");
        }
    }
}

测试类

//如何构建静态内部类对象和调用静态内部类中的方法
public class StaticInnerGrammarDemo {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// 如何构建静态内部类对象
		// ①调用外部类中的静态方法
		Outer.display();
		System.out.println("\n---------------\n");
		//这里面的构造语句含义不同
		//new Outer.Inner()当前的静态内部类不是属于外部对象的,而是属于外部类的
		Outer.Inner inner = new Outer.Inner();
		inner.doSomething();//调用静态内部类的普通方法
		
		System.out.println("\n-------------------------\n");
		
		Outer.Inner.invoke();//调用静态内部类的静态方法
	}
}

1、静态内部类中如何访问相同属性名的变量

public class Outer2 {

    //如果有人要问为什么在外部类中可以调用静态属性,是因为静态属性是优先参生的,比对象的优先级高
    private static String name = "独孤求败";

    // 静态内部类
    static class Inner {
        String name = "楚留香";
        static String name2 = "小鱼儿";

        /**
         * 普通方法
         */
        public void doSomething() {
            String name = "陆小凤";
            System.out.println("外部类静态属性name = " + Outer2.name);// 外部类的静态属性属于外部类的,不是属于外部类对象的
            System.out.println("静态内部类中的属性name  = " + this.name);
            System.out.println("静态内部类方法doSomething()中局部变量name  = " + name);

        }

        /**
         * 静态方法
         */
        public static void invoke() {
            String name = "陆小凤";
            System.out.println("外部类静态属性name = " + Outer2.name);// 外部类的静态属性属于外部类的,不是属于外部类对象的
            // System.out.println("静态内部类中的属性name  = " +this.name);//静态内部类中的静态方法不能访问静态内部类中的普通属性
            System.out.println("静态内部类中的静态属性name2  = " + name2);
            System.out.println("静态内部类方法invoke() 中局部变量name  = " + name);
        }
    }
}

测试类

public class StaticInnerGrammarDemo {

    public static void main(String[] args) {
     
        //StaticInnerGrammarDemo在这个类中添加
        System.out.println("\n-------------------------\n");
        new Outer2.Inner().doSomething();
        System.out.println("\n-------------------------\n");
        Outer2.Inner.invoke();
    }
}

1、静态内部类与静态属性和静态方法使用方式类似
2、如何构建静态内部类对象

因为静态内部类与外部类中的静态属性和静态方法平级,使用方式也类似,据此外部类调用外部类中的静态方法:外部类类名.静态方法(实参)

推导:外部类类名.静态内部类类名 实例名 = new 外部类.内部类构造方法;

3、静态内部类中的普通方法和静态方法只能访问外部类中的静态属性和静态方法,不能访问
外部类的普通属性和普通方法。
4、如何调用静态内部类中的静态方法呢?

语法:外部类.静态内部类.静态方法(实际参数列表);

5、包含了静态内部类的外部类,编译时,字节码文件的个数与class相同,静态内部类编译后的字节码文件名格式为:外部类$静态内部类类名.class

5.匿名内部类

书写在外部类中,与外部类的属性或方法平级的没有名字的内部类;或者是:书写在外部类的方法体中,与方法中局部变量平级的没有名字的内部类。

5.1.成员匿名内部类

语法:

访问权限修饰符 class 外部类类名{
            //外部类的属性和方法

            类 引用 = new 类(){
                 //匿名内部类的类体
            };     
}

语法演示:

public interface Smoking {
    /**
     * 抽某种品牌的香烟
     * @param name
     */
    void smoke(String name);
}

//创建一个类outer
class Outer {
    private int num = 56;

    // 外部类的属性,属性值是:匿名内部类对象。
    // new 的是接口,本质上:new的是接口匿名实现类的对象。因为实现类没有名字,所以使用接口名来代替
    private Smoking instance = new Smoking() {// 匿名内部类类体
        @Override
        public void smoke(String name) {
            System.out.println("喜欢抽" + name + "品牌的香烟,不错哦....");
        }
    };

    public void show(String name) {
        instance.smoke(name);
    }

}

//测试类演示:
class AnonymousGrammarDemo {
    
    public static void main(String[] args) {
        new Outer().show("大中华");
    }
}

1、创建一个类Outer2 讲解 匿名内部类中可以创建属性和方法

public class Outer2 {

    private int num = 56;

    // 外部类的属性,属性值是:匿名内部类对象。
    // new 的是接口,本质上:new的是接口匿名实现类的对象。因为实现类没有名字,所以使用接口名来代替
    private Smoking instance = new Smoking() {// 匿名内部类类体

        private int num = 59;

        public void doSomething() {
            System.out.println("匿名内部类中的方法doSomething()....");
        }

        @Override
        public void smoke(String name) {
            //在接口中调用方法是可以的,这样就不会成为垃圾代码,但是不太推荐使用
            int num = 60;
            System.out.println("外部类中的属性num = " + Outer2.this.num);
            System.out.println("匿名内部类中的属性num = " + this.num);//this:匿名内部类的对象
            System.out.println("局部变量num = " + num);
            doSomething();
            System.out.println("喜欢抽" + name + "品牌的香烟,不错哦....");
        }
    };

    public void show(String name) {
        instance.smoke(name);
    }
}

//测试类
 class AnonymousGrammarDemo {

    /**
     * @param args
     */
    public static void main(String[] args) {
        new Outer2().show("金白沙");
    }
}

5.2.局部匿名内部类

语法:

访问权限修饰符 class 外部类类名{
            
       //外部类的属性和方法

	    访问权限修饰符 返回值类型 方法名(形参列表){            

	    	//接口类型的局部变量(使用匿名内部类进行初始化)
           	 接口 引用 = new 接口(){
               	   //匿名内部类的类体	
                 };   
            }  
      }

案例:

//创建一个香烟的接口
public interface Smoking {
    /**
     * 抽某种品牌的香烟
     *
     * @param name
     */
    void smoke(String name);
}

class Outer {
    private int num = 4;

    public void show() {
        int score = 78;

        // 局部匿名内部类
        Smoking smoking = new Smoking() {
            //当前方法属于匿名内部类,而不是属于方法show()的
            //也就是说我们不通过当前smoking对象调用,是无法调用方法的
            @Override
            public void smoke(String name) {
                System.out.println("正在抽【" + name + "】牌子的香烟....");
            }

        };
        
        // 通过多态调用接口匿名实现类中实现后的方法
        smoking.smoke("大中华");
    }
}

局部匿名内部类第二种实现方式创建outer2

public class Outer2 {
    private int num = 4;

    public void show() {
        int score = 78;

        // 局部匿名内部类
        new Smoking() {
            @Override
            public void smoke(String name) {
                System.out.println("正在抽【" + name + "】牌子的香烟....");
            }
        }.smoke("金白沙");//也属于接口回调,调用接口中的方法,会调用接口匿名实现类中实现之后的方法
    }
}

局部匿名内部类中如何访问属性Outer3

public class Outer3 {
    private int num = 4;

    public void show() {
        
        //先写int num  = 78;
        //然后在局部内部类中是无法访问的因为和局部类中的变量同名
        //然后修改成下面样式,
        int num2 = 78;

        // 局部匿名内部类
        new Smoking() {
            int num = 67;
            @Override
            public void smoke(String name) {
                int num = 88;
                System.out.println("外部类中的属性num = " + Outer3.this.num);
                System.out.println("与局部匿名内部类平级的方法中局部变量num2 =  " + num2);
                System.out.println("局部匿名内部类中的属性num = " + this.num);
                System.out.println("局部匿名内部类中方法中的局部变量num = " + num);

                System.out.println("正在抽【" + name + "】牌子的香烟....");
            }
        }.smoke("金白沙");// 也属于接口回调,调用接口中的方法,会调用接口匿名实现类中实现之后的方法
    }

}

匿名内部类的特点:
1、匿名内部类只能使用一次。(类比:现实中的一次性筷子)
2、包含了匿名内部类的外部类,编译后,生成的字节码文件的个数 = class的个数 + 匿名内部类的个数
匿名内部类编译后的字节码文件名:外部类类名$编号.class ( 编号从1开始) 如:Outer$1.class