java内部类详解

博客介绍了Java内部类的分类,包括有名和匿名、静态和非静态内部类,阐述了各类内部类的特点和使用方式,如匿名内部类不能单独存在、静态内部类只能访问外部类静态成员等。还提及内部类编译后成独立.class文件,最后介绍了Java 8开始支持的Lambda表达式,简化了函数式接口匿名内部类语法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

分类

内部类是指在一个外部类内定义的类。

  • 按照是否有类名分为有名内部类匿名内部类
  • 按照是否有static修饰分为静态内部类非静态内部类,有static修饰的为静态内部类,没有static修饰的为非静态内部类。

1.有名内部类

Body类:
package com.jd;

/**
 * 外部类
 */
public class Body {

	/**
	 * 有名内部类
	 */
	public class Heart{

		public void beat(){
			System.out.println("正在跳动...");
		}
	}
}

Test类:
package com.jd;

import com.jd.Body.Heart;

public class Test {

	public static void main(String[] args) {
		Body body = new Body();
		Heart heart = body.new Heart();
		heart.beat();
	}
}

说明:全局有名内部类的使用方式类似于全局变量局部有名内部类的使用方式类似局部变量——它们都有固定的使用范围;

2. 匿名内部类

匿名内部类由于没有类名而不能单独存在,定义匿名内部类的同时须直接实例化该类
其语法格式如下:

 new 父类构造器([参数列表])|接口(){    
		 //匿名内部类类体
 } 
  • 普通类:普通类匿名内部类实质为普通类的子类
    示例:

     普通类:
     class Mammal {
     
     	public void move() {
     		System.out.println("正在移动......");
     	}
     }
     
     public class Sea {
     
     	Mammal whale = new Mammal() {//调用Mammal中的无参构造方法
     
     		@Override
     		public void move() {
     			System.out.println("鲸鱼靠鳍移动......");
     		}
     	};
     }
    
  • 抽象类:抽象类匿名内部类实质为抽象类的子类。
    示例:

      abstract class Mammal {
      
      	public Mammal(String name) {
      		System.out.println(name);
      	}
      
      	abstract void move();
      }
      
      public class Sea {
      
      	Mammal mammal = new Mammal("鲸鱼") {// 调用Mammal中的有参构造方法
      
      		@Override
      		void move() {
      			System.out.println("鲸鱼靠鳍移动......");
      		}
      	};
      }
    
  • 接口:接口匿名内部类实质为接口的实现类。
    示例:

      interface Mammal {
      	abstract void move();
      }
      
      public class Sea {
      
      	Mammal mammal = new Mammal() {
      
      		@Override
      		public void move() {
      			System.out.println("鲸鱼靠鳍移动......");
      		}
      	};
      }
    

匿名内部类特点

  • 匿名内部类一定是接口的实现类(该实现类仅能实现一个接口)或类(普通类或抽象类)的子类,其中new 关键字后面的类名或接口名即是该匿名内部类继承的父类或实现的接口;

  • 匿名内部类不能自定义构造方法,但是可以通过非静态代码块初始化成员变量;

  • 匿名内部类一定不能是抽象类;

  • 可以在匿名内部类中添加新的属性和方法,但是这些属性和方法不能被上转型对象所调用,只能被非上转型对象方式创建的匿名内部类对象所调用,例如:

      代码1:
      public class Test {
      
      	public static void main(String[] args) {
      
      		IMammal whale = new IMammal() {
      			public void breath() {
      				System.out.println("鲸鱼正在呼吸......");
      			}
      
      			@Override
      			public void move() {
      				System.out.println("鲸鱼靠鳍游动......");
      			}
      		};//此时匿名内部类对象为上转型对象
      		whale.breath();// 上转型对象无法调用新增的breath方法
      	}
      }
      
      interface IMammal {
      	void move();
      }
      
      代码2:
      public class Test {
      
      	public static void main(String[] args) {
      
      		new IMammal() {
      			public void breath() {
      				System.out.println("鲸鱼正在呼吸......");
      			}
      
      			@Override
      			public void move() {
      				System.out.println("鲸鱼靠鳍游动......");
      			}
      		}.breath();// 调用新增的breath方法
      	}
      }
      
      interface IMammal {
      	void move();
      }
    

3. 静态内部类

静态有名内部类

Body类:
package com.jd;

/**
 * 外部类
 */
public class Body {

	/**
	 * 静态有名内部类
	 */
	public static class Heart{

		public void beat(){
			System.out.println("正在跳动...");
		}
	}
}

Test类:
package com.jd;

import com.jd.Body.Heart;

public class Test {

	public static void main(String[] args) {
		Heart heart = new Body.Heart();
		heart.beat();
	}
}

静态匿名内部类

class Father {

	public void eat() {
		System.out.println("筷子吃饭....");
	}
}

/**
 * 外部类
 */
public class OutClass {

	/**
	 * 匿名内部类
	 */
	static Father son = new Father(){
		
		@Override
		public void eat() {
			System.out.println("筷子吃饭....");
		}
	};
}

注意

  • 如果为static内部类只能直接定义在外部类中。

     public class OutClass {
     
     	public static void main(String[] args) {
     		
     		/**
     		 * 静态有名内部类
     		 */
     		static class InClass {
     
     			public void printInfo() {
     				System.out.println("我是有名内部类");
     			}
     		}
     	}
     }
    
  • 静态内部类仅能直接访问外部类的静态成员变量和方法,可以通过创建外部类的对象间接使用非静态的成员变量和方法。

     public class OutClass {
     	
     	private double weight=72;
     	
     	public static void print(String name) {
     		System.out.println(name);
     	}
     	
     	static class InClass{
     		{
     			double weight = new OutClass().weight;//由于weight是非静态的,所以在静态内部类中使用时必须先创建外部类对象
     			print("Tom");//由于print方法为静态方法,所以可以直接使用。
     		}
     	}
     }
    
  • 在非外部类中定义的内部类和局部变量一样,其使用范围从定义的位置开始到其所在直接语句块结束。

      public class OutClass {
      	public static void main(String[] args) {
      		if(args!=null) {
      			class InClass{
      				
      			}
      		}
      		InClass inClass = new InClass();//无法创建对象,因为内部类作用范围无法作用到这里
      	}
      }
    
  • 只有有名静态内部类中才允许有静态成员(静态属性、静态代码块和静态方法)。

特点

  • 内部类是一个独立的类:编译之后内部类会被编译成独立的.class文件,如果该内部类为有名内部类,则有名内部类字节码文件名为外部类的类名+$+内部类类名;如果为匿名内部类,则匿名内部类字节码文件名为外部类类名+$+数字;

  • 普通外部类、抽象类和接口可以有内部类(匿名的或有名的);

  • 内部类可以直接定义在类中,也可以定义在方法或代码块中;其中直接定义在外部类中的内部类可以有public、protected、默认的和private四种访问权限修饰(普通外部类、接口和抽象类只能使用public和default修饰),也可以使用static修饰( static不能修饰普通外部类、接口和抽象类);但是定义在方法或代码块中的内部类不能有访问修饰符修饰,也不能有static修饰。

  • 内部类可以访问外部类的所有访问权限的成员变量,如下例:

      public class OutClass {
      	
      	private String name;
      
      	class InClass{
      
      		{
      			System.out.println(name);
      		}
      	}
      }
    
  • 在局部变量作用的范围内,如果定义的内部类需要使用该局部变量,则该变量必须有final修饰。

      代码1
      public class OutClass {
      
      	public void print(final String name) {//由于局部变量name要在InClass内部类中使用,所以需要加final;方法参数前面加final修饰表示只能在调用方法时为该参数指定值,不允许再在方法体中进行二次修改。
      		final int weight = 9;//由于局部变量weight要在InClass内部类中使用,所以需要加final;
      		class InClass{
      			public void print() {
      				System.out.println(name+","+weight);
      			}
      		}
      		new InClass().print();
      	}
      	
      	public static void main(String[] args) {
      		new OutClass().print("Tom");
      	}
      }
      
      代码2
      public class OutClass {
      
      	public static void main(String[] args) {
      		final int i = 8;//由于局部变量i要在InClass内部类中使用,所以需要加final;
      		class InClass {
      			public void print() {
      				System.out.println(i);
      			}
      		}
      		InClass inClass = new InClass();
      		inClass.print();
      	}
      }
    

    注意:从 Java 8开始,如果定义的内部类需要使用该局部变量,则该变量可以不使用final修饰。

Lambda 表达式

Java支持Lambda 表达式始于Java 8,它的出现简化了函数式接口匿名内部类的语法
其表达式语法如下:

([参数1], [参数2], [参数3],.... [参数n])->{代码块}

示例:

匿名内部类:

@FunctionalInterface
interface IArrayUtil{
	void iterate(Object [] array);
}

public class Test {
	
	public static void main(String args[]){
		IArrayUtil arrayUtil = new IArrayUtil() {
			@Override
			public void iterate(Object[] array) {
				for (Object obj : array) {
					System.out.println(obj);
				}
			}
		};
		
		arrayUtil.iterate(new String[] {"小张","小王"});
	}
}

Lambda 表达式:

@FunctionalInterface
interface IArrayUtil {
	void iterate(Object[] array);
}

public class Test {

	public static void main(String args[]) {
		IArrayUtil arrayUtil = (Object[] array) -> {
			for (Object obj : array) {
				System.out.println(obj);
			}
		};

		arrayUtil.iterate(new String[] { "小张", "小王"});
	}
}
  • 如果方法没有返回值且只有一行代码,则Lambda表达式语法可以是这种形式:

    ([参数1], [参数2], [参数3],… [参数n])->单行语句

    如下例:

    匿名内部类:

      @FunctionalInterface
      interface IMammal {
      	void move(String name);
      }
      
      public class Test {
      
      	public static void main(String[] args) {
      		IMammal whale = (name) -> {
      			System.out.println(name+"正在移动......");
      		};
      		whale.move("鲸鱼");
      	}
      }
    

    Lambda 表达式:

      @FunctionalInterface
      interface IMammal {
      	void move(String name);
      }
      
      public class Test {
      
      	public static void main(String[] args) {
      		IMammal whale = (name) -> System.out.println(name+"正在移动......");
      		whale.move("鲸鱼");
      	}
      }
    
  • 如果方法有返回值且只有一行代码,则Lambda表达式语法可以是这种形式:

      ([参数1], [参数2], [参数3],.... [参数n])->表达式
    

    如下例:

    匿名内部类:

      @FunctionalInterface
      interface IComputer {
      	int add(int a, int b);
      }
      
      public class Test {
      
      	public static void main(String[] args) {
      		IComputer computer = (a, b) -> {
      			return a+b;
      		};
      		int result = computer.add(1,2);
      		System.out.println(result);
      	}
      }
    

    Lambda 表达式:

      @FunctionalInterface
      interface IComputer {
      	int add(int a, int b);
      }
      
      public class Test {
      
      	public static void main(String[] args) {
      		IComputer computer = (a, b) -> a+b;
      		int result = computer.add(1,2);
      		System.out.println(result);
      	}
      }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值