Java内部类

                                                        Java内部类

1.内部类:

         我们知道一个文件中只能有一个public类,如果还要定义一个类(包括接口)只能是默认的不能带有修饰符。而内部类则不然,内部类是指在一个类中(外部类)再定义一个类(内部类),内部类这是相当于外部类的一个属性,类似的内部类分为成员内部类,局部内部类,静态内部类,匿名内部类;内部类的定义不像外部类一样必须使用public或这默认的,他的修饰符可以像所有变量一样可以用public,default,protected和private修饰,也可以是静态的。它的命名也不用担心会和外部类产生冲突,可以自己定义。

         内部类平时使用的不多,最多的还是用在事件监听的过程中。

2.成员内部类:

         在内部类中可以随意的使用外部类的成员方法和成员变量,尽管这些类的成员被修饰为private.

         内部类的实例一定要绑定在外部类的实例上,如果从外部类中初始化一个内部类的对象,那么内部类对象就会绑定在外部类的对象上。

 

public class OuterClass {
	innerClass in = new innerClass(); // 在外部类实例化内部类对象引用
	
	public void ouf() {
		in.inf(); // 在外部类方法中调用内部类方法
	}
	
	class innerClass {
		innerClass() { // 内部类构造方法
		}
		
		public void inf() { // 内部类成员方法
		}
		
		int y = 0; // 定义内部类成员变量
	}
	
	public innerClass doit() { // 外部类方法,返回值为内部类引用
		// y=4; //外部类不可以直接访问内部类成员变量
		in.y = 4;
		return new innerClass(); // 返回内部类引用
	}
	
	public static void main(String args[]) {
		OuterClass out = new OuterClass();
		// 内部类的对象实例化操作必须在外部类或外部类中的非静态方法中实现
		OuterClass.innerClass in = out.doit();
		OuterClass.innerClass in2 = out.new innerClass();
	}
}
 

 


注意:

1.内部类的对象实例化操作必须在外部类或外部类的非静态方法中实现,如果在这之外(静态方法、外部类)中则需要使用外部类的实例对象来进行,如上面的main函数中。

2.当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:(外部类.this表示外部类对象)内部类被实例化后也存放在堆中,而 外部类.this可以活动外部类在堆中的对象。

 

外部类.this.成员变量
外部类.this.成员方法
3. 虽然成员内部类可以无条件地访问外部类的成员,但是却不能对外部类属性进行赋值或修改,只能定义一个变量来接收。而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问。
4.成员内部类不能含有static的变量和方法(这些只能属于外部类,我们叫类方法和类属性)。因为成员内部类需要先创建了外部类,才能创建它自己的。
5.内部类向上转型为接口
       如果将一个权限修饰符为private的内部类向上转型为其父类对象,或者直接向上转型为一个接口,在程序中就可以完全隐藏内部类的具体实现过程。
public class Test {
	public static void main(String args[]) {
		OuterClass2 out = new OuterClass2(); // 实例化一个OuterClass2对象
		// 调用doit()方法,返回一个OutInterface接口
		OutInterface outinter = out.doit();
		outinter.f(); // 调用f()方法,这样你根本不知道f方法是如何实现的,很好的进行了封装,这是内部类的最基本用途。
	}
}

interface OutInterface { // 定义一个接口
	public void f();
}

class OuterClass2 {
	// 定义一个内部类实现OutInterface接口
	private class InnerClass implements OutInterface {
		InnerClass(String s) { // 内部类构造方法
			System.out.println(s);
		}
		
		public void f() { // 实现接口中的f()方法
			System.out.println("访问内部类中的f()方法");
		}
	}
	
	public OutInterface doit() { // 定义一个方法,返回值类型为OutInterface接口,对InnerClass进行了自动向上转型
		return new InnerClass("访问内部类构造方法");
	}
}
 输出:访问内部类的构造方法           访问内部类中的f()方法
3.局部内部类
         内部类不仅可以在类中进行定义,也可以在类的局部位置定义,如在类的方法或任意的作用域中均可以定义内部类
interface OutInterface { // 定义一个接口
}
public class OuterClass {
	public OutInterface doit(final String x) { // doit()方法参数为final类型
		// 在doit()方法中定义一个内部类
		class InnerClass implements OutInterface {
			InnerClass(String s) {
				s = x;
				System.out.println(s);
			}
		}
		return new InnerClass("doit");
	}
}
            我们会发现doit()的参数设置为final类型。如果需要在方法体中使用局部变量,该局部变量需要被设置为final类型(该方法中的内部类只能访问方法中final类型的局部变量),因为在方法中定义的局部变量相对于该类来说是一个常量,我们不能对它进行改变。它的生命周期超过方法运行的生命周期(该方法被销毁了,但方法的返回对象还要存在),如果可以改变的话可能造成一个变量到时可能被两个拥有,但他们对应的值又不相同。所以该局部变量被设置为final。所以不能在内部类中该局部变量的值(这点和成员内部类中也不能改外部类的属性值一样)。
             而且局部变量就像方法里的局部变量一样,是不能有public,private,protected以及static修饰的。
4.匿名内部类
         匿名内部类是我们使用最多的内部类,最主要的作用就是实现接口对里面的方法进行重写,它大量的应用在事件处理和线程里面,可以很好的帮组我们对代码进行维护。
interface E{
	public void A();
}
public class B{
	public E creat(final int a ){
		return new E(){  //声明一个内部类,默认继承E接口
			private int i = a;
			public int getvalue(){
				return i;
			}
			@Override
			public void A() {
				// TODO Auto-generated method stub
				
			}
		};
	}
}
 
         由于匿名内部类没有名称,所以匿名内部类使用默认的构造方法类实例化,匿名内部类末尾的分号并不是代表定义内部类结束的标识,而是代表创建E应用表达式的标识。
         匿名内部类的创建必须要基于接口
         同局部内部类一样方法体中的变量必须定义为final。理由同上
 
5.静态内部类(嵌套内部类)         静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。但他不能声明为private,一般用public修饰,方便调用。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类 似,并且它不能使用外部类的非static成员变量或者方法,这点和普通内部类不同。这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外 部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。综合起来就是:
1.不能从静态内部类的对象中访问非静态外部类的对象
2.如果创建静态内部类的对象,不需要其外部类的对象
public class B {
	int x=100;
	static class Inner{
		void doitInner(){
			System.out.println("外部类"+x); //这里会编译报错
		}
		//进行程序测试时,如果在每个Java文件中都设置一个main方法,
		//将出现很多额外的代码,而程序本身不需要这些方法时可以将main函数写入内部类中,这样只要用外部类.内部类就可以调用main函数了,测试完成时只要把这给类给删除就可以了。
		public static void main(String args[]){
			System.out.println("a");
		}
	}
}
 
6.内部类的继承
         内部类的继承是指    普通类extends内部类,但是继承内部类比继承普通类复杂,要设置专门的语法来完成(某个类继承内部类时,只能使用带继承类的外部类类型的参数的构造方法,否则编译不能通过),同时要调用super的构造方法。由于内部类的继承用到较少又比较复杂,这里只做一个简单的介绍。
public class C extends ClassA.ClassB{              //继承内部类ClassB
	public C(ClassA a){
		a.super();
	}
	
}
class ClassA{
	class ClassB{
		
	}
}
 7.内部类的编译:
           内部类编译后会产生外部类.class和外部类$内部类.class两个编译文件,而对于匿名内部类则会用序号1-n排列代表1-n个匿名内部类。外部类$序号.class。
8.总结使用内部类的好处:
1.每个内部类都能独立的继承一个接口,所以无论外部类是否已经继承了该接口对里面的方法有没有重写,对于内部类都没有影响。而且外部类可以定义多个内部类继承同一个接口,进行不同的实现。内部类使得多继承的解决方案变得完整,

2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。

3.方便编写事件驱动程序及线程的编码

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值