内部类 java基础复习

总结:
1、内部类可以操作外部类中所有的成员方法和成员变量,包括private修饰过的。Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着,这样就使得内部类对象始终可以访问其外部类对象。
2、任何非静态内部类中,都不能有静态数据。
3、编译完成后,内部类的字节码文件的格式是:外部类名$内部类名。
4、当外部类、内部类、内部类方法中都包含同一字段或方法时,当方法调用那个字段或方法,首先调用的是方法中的字段,如果想调用类中的字段,可以用:this.字段名,如果想调用外部类中的字段,可以用:outer.this.字段名。
5、声明内部类:
To instantiate an inner class, you must first instantiate the outer class. Then, create the inner object within the outer object with this syntax:
  OuterClass.InnerClass innerObject = outerObject.new InnerClass(); 
Because you are actually inside the class which also is the outerObject you just use "this" instead of the outerObject.In instance methods of the outer class you can create an inner class object with simply "new" and its enclosing object will automatically be "this."

     创建非静态内部类对象,一定要先创建起相应的外部类对象,这样做的好处是体现了封装性,也可以在外部类定义一个返回内部类对象的方法来实现。

 

public class Outer {
	private int age = 10;
	private Inner in1 = new Inner();//在外部类中,直接定义内部类对象
	Outer(){}
	Outer(int value){age = value;System.out.println("Outer.age:"+age);}
	public void print(){
		System.out.println("Outer.age:"+age);
	}
	public Inner getInnerInstance(){
		return new Inner();//返回内部类的一个引用
	}
	class Inner{
		private int age = 34;
		Inner(){System.out.println("Outer.Inner");}
		public void print(){
			int age = 23;
			System.out.println("#:"+age);//调用的是方法中的字段
			System.out.println("##:"+this.age);//调用内部类中的字段
			System.out.println("###:"+Outer.this.age);//调用外部类中的字段
		}
	}
	//当main方法在 外部类 的内部
	public static void main(String[] args) {
		
		System.out.println("in1...");
		Outer out = new Outer();
		out.in1.print();
//		in1.print();//编译错误:Connot make a static reference to the non-static field in1
		
		System.out.println("in2...");
		Inner in2 = out.getInnerInstance();//可以直接引用,不需要属性引用符
		in2.print();
		
		System.out.println("in4...");
		Outer.Inner in4 = out.new Inner();
		in4.print();

		System.out.println("in6...");
		Inner int6 = new Outer().new Inner();
		int6.print();					
	}	
}
class TestInner{
	//当main方法在 外部类 的外部
	public static void main(String[] args){
		System.out.println("in3...");
		Outer out = new Outer();	
		Outer.Inner in3 = out.getInnerInstance();//内部类作为其外部类的一个成员(注意与in2 比较)
//		Outer.Inner in = new Inner();//编译错误,不能直接用new去声明内部类,编译错误:Inner connot be resolved to a type.

		System.out.println("in5...");
		Outer.Inner in5 = out.new Inner();
		in5.print();
		
//		in1.print();//编译错误:in1 connot be resolved
//		out.in1.print();//编译错误:out.in1 connot be resolved,因为Inner是private修饰的,只能够在Outer内部进行访问
	}
}


 

6、内部类的继承
     当一个类继承自一个内部类时,缺省的构造器不可用。因为每一个内部类都有一个指向外部类的引用,在继承一个内部类,必须先创建一个外部类,通过这个外部类引用来调用其内部类的构造方法。如果继承的内部类是一个静态内部类,则就不需要这样,直接super()调用即可。


class TestExtend extends Outer.Inner{
	TestExtend(Outer out){
		out.super();
	}
	public static void main(String[] args){
		Outer out = new Outer();
		TestExtend ex = new TestExtend(out);
		ex.print();
	}
}

 
     内部类可以被重载吗?注意,当你继承了某个外围类的时候,内部类并没有发生什么特别神奇的变化。这两个内部类是完全独立的两个实体,各自在自己的命名空间内。


class OtherOuter extends Outer{
	class Inner {
		Inner(){System.out.println("OtherOuter.Inner");}
		public void print(){
			System.out.println("OtherOuter.print()");
		}
	}
	public static void main(String[] args){
		OtherOuter other = new OtherOuter();
		other.new Inner().print();
	}
}
输出:
Outer.Inner
OtherOuter.Inner
OtherOuter.print()

 
   可以明确地继承某个内部类,只要添加extends Outer.Inner


class OtherOuter extends Outer{
	class Inner extends Outer.Inner{//
		Inner(){System.out.println("OtherOuter.Inner");}
		public void print(){
			System.out.println("OtherOuter.print()");
		}
	}
	public static void main(String[] args){
		OtherOuter other = new OtherOuter();
		other.new Inner().print();
	}
}
输出:
Outer.Inner
Outer.Inner
OtherOuter.Inner
OtherOuter.print()

 
7、内部类的重要应用
     一个类从另一个类派生出来,又要实现一个接口。但在接口中定义的方法与父类中定义的方法的意义不同,则可以利用内部类来解决这个问题。

 

interface People{
	void print();
}
class Parents{
	public void print(){System.out.println("Parents...");}
}
class Child extends Parents{
	class PeopleImpl implements People{	
		public void print() {//public不可缺少
			System.out.println("Override People.print");
		}		
	}
	PeopleImpl getPeopleImpl(){
		return new PeopleImpl();
	}
}
class Test3{
	public static void main(String[] args){
		Child c = new Child();
		c.print();//打印结果:Parents...
		c.getPeopleImpl().print();//打印结果:Override People.print
	}
}

 

        类似的,内部类可以解决C++多重继承所解决的问题。在实际应用中,内部类又可以实现很多软件工程思想,比如:

 

 class DataStructure {
    private final static int SIZE = 15;
    private int[] arrayOfInts = new int[SIZE];
    
    public DataStructure() {
        for (int i = 0; i < SIZE; i++) {
            arrayOfInts[i] = i;
        }
    }
    
    public void printEven() {
        InnerEvenIterator iterator = this.new InnerEvenIterator();//创建内部类遍历
        while (iterator.hasNext()) {
            System.out.print(iterator.getNext() + " ");
        }
    }
  
    private class InnerEvenIterator {
        private int next = 0;
        
        public boolean hasNext() {
            return (next <= SIZE - 1);
        }
        
        public int getNext() {
            int retValue = arrayOfInts[next];
            next += 1;
            return retValue;
        }
    }
    
    public static void main(String s[]) {
        DataStructure ds = new DataStructure();
        ds.printEven();//结果:0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 
    }
}




 

特殊的内部类,除了具有普通内部类的特点,还有自己的一些独有特性


1、静态内部类:将内部类声明为static。要创建嵌套类的对象,并不需要其外围类的对象。
Outer.Inner in = new Outer.Inner(); 不能从嵌套类的对象中访问非静态的外围类对象(包括静态变量和静态方法)。静态内部类中可以定义静态或者非静态的成员。

2、局部内部类:在方法中定义的内部类称为局部内部类。只能访问方法中的final类型的局部变量,局部内部类不允许有访问修饰符。

3、匿名内部类:顾名思义,没有名字的内部类。匿名内部类为局部内部类,所以局部内部类的所有限制对其都有效,除此之外还要注意以下几个原则:
(1)匿名内部类必须扩展一个基类或实现一个接口,但是不能有显式的extends和implements子句。
(2)匿名内部类必须实现父类以及接口中的所有抽象方法。
(3)匿名内部类不能有构造方法,总是使用父类的无参构造方法来创建实例。如果是实现了一个接口,则其构造方法是Object()。
(4)匿名内部类编译后的命名为:OuterClass$n.class,其中n是一个从1开始的整数,如果在一个类中定义了多个匿名内部类,则按照他们的出现顺序从1开始排号。
(5)匿名内部类不能定义任何静态成员、方法和类。


class Parcel {
	public Outer cont() {
		return new Outer() {//创建一个继承Outer的匿名类
			private int age = 11;
			public void print() {
				System.out.println("Parcel.age:"+age);
			}
		}; // 在这里需要一个分号
	}
	public Outer cont(int age){//不要求变量age 一定是final 的。因为age 被传递给匿名类的基类的构造器,它并不会在匿名类内部被直接使用。
		return new Outer(age){
			private int age = 21;
			public void print() {
				System.out.println("Parcel.age:"+age);
			}
		};
	}
	/*
	 * 参数若没有final,编译报错:"Cannot refer to a non-final variable value inside an
	 * inner class defined in a different method."
	 * 匿名内部类,它要使用一个在它的外部定义的对象,编译器会要求其参数引用是final 型的
	 */
	public Outer cont2(final int value){
		return new Outer(value){
			private int age = value;
			public void print() {
				System.out.println("Parcel.age:"+age);
			}
		};
	}
	public static void main(String[] args) {
		Parcel p = new Parcel();
		
		Outer c = p.cont();
		c.print();//结果:Parcel.age:11
		
		c=p.cont(7);//因为7 被传递给匿名类的基类的构造器,它并不会在匿名类内部被直接使用
		c.print();//Outer.age:7  Parcel.age:21
		
	}
}

 

相关面试题收集:


1、Anonymous Inner Class(匿名内部类)是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
匿名的内部类是没有名字的内部类。不能extends(继承) 其它类,
但一个内部类可以作为一个接口,由另一个内部类实现。

2、Static Nested Class 和 Inner Class的不同
答:Nested Class (一般是C++的说法),Inner Class (一般是JAVA的说法)。
Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用上。
注: 静态内部类(Inner Class)意味着
1)创建一个static内部类的对象,不需要一个外部类对象,
2)不能从一个static内部类的一个对象访问一个外部类对象















你可能感兴趣的:(内部类 java基础复习)