Java——内部类

1、内部类:
       定义在另外一个类里面的类,就叫做内部类,为了区别,把外面的类称为外部类。
  
  2、分类
  根据内部类的所在的位置不同:
  (1)成员内部类:外部类中方法外
  (2)局部内部类:方法体内,(虽然也可以在代码块内,但是不讨论这个)
  
  
  成员内部类:
  (1)有static修饰的:静态成员内部类,我们通常就简称为静态内部类
  (2)没有static修饰的:非静态成员内部类,我们通常就简称为成员内部类
  【修饰符】  class  外部类{
          【其他修饰符】  static class 静态内部类{
          }
          【其他修饰符】   class 非静态成员内部类{
          }
  }
  
  【修饰符】  class  外部类  【extends 父类】  【implements 父接口们】{
          【其他修饰符】  static class 静态内部类   【extends 父类】  【implements 父接口们】{
          }
          【其他修饰符】   class 非静态成员内部类   【extends 父类】  【implements 父接口们】{
          }
  }
  说明:外部类、内部类的父类、父接口没有关系,各是各的
  
  
  局部内部类:
  (1)有名字的局部内部类:简称局部内部类
  (2)没名字的局部内部类:简称匿名内部类
  
  局部内部类的语法格式:
  【修饰符】  class  外部类  【extends 父类】  【implements 父接口们】{
          【修饰符】 返回值类型   方法名(【形参列表】){
                  【修饰符】  class 有名字的局部内部类   【extends 父类】  【implements 父接口们】{
                      ...
                  }
          }
  }
  
  匿名内部类的语法格式:
      特殊

import java.util.Arrays;
import java.util.Comparator;

/*
 * 一、匿名内部类
 * 语法格式:
 * 	new 父类名(【实参列表】){
 * 		类的成员列表
 * 	}
 * 说明:如果你子类调用的是父类的无参构造,那么()中实参列表不用写,如果子类调用的是父类的有参构造,那么就在()中传入实参列表
 * 或
 * new 父接口名(){
 *    类的成员列表
 * }
 * 
 * 特殊:声明匿名内部类与创建它的对象是一起完成的。即匿名内部类只有唯一的对象。
 * 
 */
public class TestAnonymousInner {
	@SuppressWarnings("unchecked")
	public static void main(String[] args) {
		//1、需求1:要声明一个Object的子类,匿名子类,
		//并在子类中声明一个方法public void test(){}打印“hello匿名内部类"
		
		//下面这段代码,声明了匿名内部类,也创建了它的对象
		//但是没有说这个对象干什么,编译不通过的。
/*		new Object(){
			public void test(){
				System.out.println("hello匿名内部类");
			}
		}*/
		
		//(1)我们可以把这个对象,赋值给一个变量
		//多态引用
		Object obj1 = new Object(){
			public void test(){
				System.out.println("hello匿名内部类");
			}
		};
		System.out.println(obj1.getClass());//获取对象的运行时类型
		System.out.println(obj1);//打印对象时,自动对象的toString()
		
		//这是另一个Object的匿名子类的对象
/*		Object obj2 = new Object(){
			public void test(){
				System.out.println("hello匿名内部类");
			}
		};*/
		
//		(2)我们可以用这个对象,直接调用方法
		//匿名内部类的匿名对象.方法()
		new Object(){
			public void test(){
				System.out.println("hello匿名内部类");
			}
		}.test();
		
		//java.util.Comparator接口
		//我要在这里声明一个比较器类型,用于比较两个圆的半径大小
		//把一个Comparator接口的匿名实现类对象,赋值给Comparator的变量
		//多态引用
/*		Comparator c = new Comparator(){
			@Override
			public int compare(Object o1, Object o2) {
				Circle c1 = (Circle) o1;
				Circle c2 = (Circle) o2;
				if(c1.getRadius() > c2.getRadius()){
					return 1;
				}else if(c1.getRadius() < c2.getRadius()){
					return -1;
				}
				return 0;
			}
		};
		
		System.out.println(c.compare(new Circle(1), new Circle(2)));*/
		
		Circle[] all = new Circle[3];
		all[0] = new Circle(3);
		all[1] = new Circle(2);
		all[2] = new Circle(1);
		
		//匿名内部类的匿名对象作为实参使用
		Arrays.sort(all, new Comparator(){
			@Override
			public int compare(Object o1, Object o2) {
				Circle c1 = (Circle) o1;
				Circle c2 = (Circle) o2;
				if(c1.getRadius() > c2.getRadius()){
					return 1;
				}else if(c1.getRadius() < c2.getRadius()){
					return -1;
				}
				return 0;
			}
		});
		
		
	}
}
/*class RadiusComparator implements Comparator{

	@Override
	public int compare(Object o1, Object o2) {
		Circle c1 = (Circle) o1;
		Circle c2 = (Circle) o2;
		if(c1.getRadius() > c2.getRadius()){
			return 1;
		}else if(c1.getRadius() < c2.getRadius()){
			return -1;
		}
		return 0;
	}
	
}*/

class Circle{
	private double radius;

	public Circle(double radius) {
		super();
		this.radius = radius;
	}

	public double getRadius() {
		return radius;
	}

	public void setRadius(double radius) {
		this.radius = radius;
	}

	@Override
	public String toString() {
		return "Circle [radius=" + radius + "]";
	}
	
}

类的成员:
  1、属性:成员变量
  2、方法:成员方法
  3、构造器
  4、代码块
  5、内部类:成员内部类
  
  其中1、2是代表这类事物的特征
  其中3、4是初始化类和对象用的
  其中5协助完成2的功能的实现,表现
  
  什么情况下会用到成员内部类(方法外声明的)?
  当描述一个事物时,发现它的内部还有一个完整的结构需要用一个类来描述;
  并且发现这内部的结构,如果独立存在是没有意义的,必须在这个外部类中才有意义。而且这个内部结构只为这个外部类服务。
  
  例如:Body身体,发现它内部还有完整的结构,例如:心脏
  发现心脏单独创建对象没有意义,只有在Body对象中才有意义,而且只为Body对象服务。

/*
 * 成员内部类分为两种:
 * 1、静态成员内部类,简称静态内部类
 * 【修饰符】 class 外部类{
 * 		【其他修饰符】 static class 内部类{
 * 		}
 * }
 * 【修饰符】 class 外部类  【 extends 父类】 【implements 父接口们】{
 * 		【其他修饰符】 static class 内部类  【 extends 父类】 【implements 父接口们】{
 * 		}
 * }
 * 注意:只有成员内部类才能用static修饰,其他的外部类,局部内部类等都不可以用static修饰
 * 
 * 2、非静态成员内部类
 * 【修饰符】 class 外部类{
 * 		【其他修饰符】  class 内部类  {
 * 		}
 * }
 * 【修饰符】 class 外部类 【 extends 父类】 【implements 父接口们】{
 * 		【其他修饰符】  class 内部类  【 extends 父类】 【implements 父接口们】{
 * 		}
 * }
 */
public class TestMemberInner {

}
class Outer{
	//静态内部类
	static class Inner{
		
	}
	
	//非静态内部类
	class Nei{
		
	}
}

静态内部类: 

/*
 * 二、静态内部类
 * 
 * 1、特点
 * (1)静态内部类中,可以出现原本类中能够定义的所有的成员
 * 属性:可以有静态属性和非静态属性
 * 方法:可以有静态方法和非静态方法
 * 		如果静态内部类是抽象类的话,还可以定义抽象方法
 * 构造器:有参、无参
 * 代码块:可以有静态代码块和非静态代码块
 * 内部类:允许,很少再写内部类(不讨论内部类的内部类)
 * 
 * (2)静态内部类中不能使用外部类的非静态的成员
 * (3)在外部类中,使用静态内部类,和使用其他的类一样的原则
 * 如果使用静态内部类的静态成员,直接“静态内部类名.”
 * 如果使用静态内部类的非静态成员,直接“静态内部类对象名.”
 * (4)在外部类的外面,使用静态内部类
 * 如果使用静态内部类的静态成员,直接“类名.”
 * 		使用外部类名.静态内部类名.静态方法
 * 		使用import 包.外部类名.静态内部类名;  在代码中使用   “静态内部类名.”
 * 如果使用静态内部类的非静态成员,“静态内部类对象名.”
 * 
 * (5)静态内部类不会随着外部类的初始化一起初始化,而是要在使用到这个静态内部类是才会初始化
 * 
 * 
 * 2、结论
 * (1)同级的来说静态的不能直接使用非静态的
 * (2)访问一个类的静态成员,用“类名.”即可,
 * 	   访问一个类的非静态成员,用“对象名.”即可,
 * (3)一个类需要初始化,得用到这个类
 */
public class TestStaticInner {
	public static void main(String[] args) {
/*//		Inner.test();//上面有导包语句,import 包.外部类名.静态内部类名;
		
		Outer.Inner.test();//外部类名.静态内部类名.静态方法
		
//		Inner in = new Inner();//上面有导包语句,import 包.外部类名.静态内部类名;
		Outer.Inner in = new Outer.Inner();
		in.method();*/
		
		Outer out = new Outer();
		out.outMethod();
	}
}
class Outer{
	private int i = 1;
	private static int j = 2;
	
	static{
		System.out.println("外部类的静态代码块");
	}
	
	static class Inner{
		static{
			System.out.println("静态内部类的代码块");
		}
		
		public void method(){
			System.out.println("静态内部类的非静态方法");
//			System.out.println(i);//错误
			System.out.println(j);
		}
		
		public static void test(){
			System.out.println("静态内部类的静态方法");
		}
	}
	
	public void outMethod(){
		Inner in = new Inner();
		in.method();//非静态方法,用对象名.访问
		
		Inner.test();//静态方法,用类名.访问
	}
}

非静态成员内部类:

//import com.atguigu.test02.Outer.Inner;

/*
 * 二、静态内部类
 * 
 * 1、特点
 * (1)静态内部类中,可以出现原本类中能够定义的所有的成员
 * 属性:可以有静态属性和非静态属性
 * 方法:可以有静态方法和非静态方法
 * 		如果静态内部类是抽象类的话,还可以定义抽象方法
 * 构造器:有参、无参
 * 代码块:可以有静态代码块和非静态代码块
 * 内部类:允许,很少再写内部类(不讨论内部类的内部类)
 * 
 * (2)静态内部类中不能使用外部类的非静态的成员
 * (3)在外部类中,使用静态内部类,和使用其他的类一样的原则
 * 如果使用静态内部类的静态成员,直接“静态内部类名.”
 * 如果使用静态内部类的非静态成员,直接“静态内部类对象名.”
 * (4)在外部类的外面,使用静态内部类
 * 如果使用静态内部类的静态成员,直接“类名.”
 * 		使用外部类名.静态内部类名.静态方法
 * 		使用import 包.外部类名.静态内部类名;  在代码中使用   “静态内部类名.”
 * 如果使用静态内部类的非静态成员,“静态内部类对象名.”
 * 
 * (5)静态内部类不会随着外部类的初始化一起初始化,而是要在使用到这个静态内部类是才会初始化
 * 
 * 
 * 2、结论
 * (1)同级的来说静态的不能直接使用非静态的
 * (2)访问一个类的静态成员,用“类名.”即可,
 * 	   访问一个类的非静态成员,用“对象名.”即可,
 * (3)一个类需要初始化,得用到这个类
 */
public class TestStaticInner {
	public static void main(String[] args) {
/*//		Inner.test();//上面有导包语句,import 包.外部类名.静态内部类名;
		
		Outer.Inner.test();//外部类名.静态内部类名.静态方法
		
//		Inner in = new Inner();//上面有导包语句,import 包.外部类名.静态内部类名;
		Outer.Inner in = new Outer.Inner();
		in.method();*/
		
		Outer out = new Outer();
		out.outMethod();
	}
}
class Outer{
	private int i = 1;
	private static int j = 2;
	
	static{
		System.out.println("外部类的静态代码块");
	}
	
	static class Inner{
		static{
			System.out.println("静态内部类的代码块");
		}
		
		public void method(){
			System.out.println("静态内部类的非静态方法");
//			System.out.println(i);//错误
			System.out.println(j);
		}
		
		public static void test(){
			System.out.println("静态内部类的静态方法");
		}
	}
	
	public void outMethod(){
		Inner in = new Inner();
		in.method();//非静态方法,用对象名.访问
		
		Inner.test();//静态方法,用类名.访问
	}
}

局部内部类:

/*
 * 四、局部内部类(最少使用的一种,几乎见不着)
 * 1、声明的位置很特殊:在方法体内
 * 
 * 2、特点
 * (1)局部内部类的修饰符,只能有abstract或final
 * (2)有作用域
 * (3)如果局部内部类在静态方法中,不能使用外部类的非静态成员
 * (4)在局部内部中,可以使用当前局部内部类所在方法的局部变量,
 * 但是要求,这个局部变量必须是final的常量。
 * 
 * 在Java8时,如果某个局部变量被局部内部类使用了,会自动添加final变为常量,一旦变为常量,它的值就不能修改了。
 * 
 * 为什么它要这么要求?加final
 * 避免局部内部类对象被返回到外部类的外面使用时,访问不到这个局部变量,所以要把这个局部变量变为final的常量。
 * 
 */
public class TestLocalInner {
	public static void main(String[] args) {
		Outer out = new Outer();
		Father in = out.test();//在外部类的外面虽然不能使用局部内部类,但是可以得到它的对象
		System.out.println(in.getClass());
		in.method();//在这里仍然可以访问到这个a,那么这个a就不能存在栈中,得挪到方法区,变为常量
	}
}
abstract class Father{
	public abstract void method();
}
class Outer{
	private int i = 1;//成员变量,实例变量,非静态成员变量
	private static int j = 2;//成员变量,类变量,静态变量
	
	public Father test(){
//		Inner in = new Inner();
		
		final int a = 10;//局部变量==>局部的常量
		
		//局部内部类
		class Inner extends Father{
			public void method(){
				System.out.println(i);
				System.out.println(j);
				System.out.println(a);
			}
		}
		
		Inner in = new Inner();
		in.method();
		
		return in;
	}
	
	public void method(){
//		Inner in = new Inner();
	}
	
	public static void fun(){
		//局部内部类
		class Inner{
			public void method(){
//				System.out.println(i);//是因为fun方法是静态的
				System.out.println(j);
			}
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值