使用静态内部类
定义内部类非常简单,只要把一个类放在另一个类内部定义即可。此处的“类内部”包括类中的任何位置,甚至在方法中也可以定义内部类(方法里定义的内部类被称为局部内部类)
public class Cow {
private double weight;
//外部类的两个重载构造器
public Cow(){
}
public Cow(double weight){
this.weight=weight;
}
//定义一个非静态的内部类
private class CowLeg{
private double length;
private String color;
//非静态内部类的两个重载构造器
public CowLeg(){}
public CowLeg(double length,String color){
this.length=length;
this.color=color;
}
public void setLength(double length){
this.length=length;
}
public double getLength(){
return length;
}
public void setColor(String color){
this.color=color;
}
public String getColor(){
return color;
}
public void info(){
System.out.println("当年牛腿的颜色为:"+color+",高:"+length);
System.out.println("本牛腿所在奶牛重:"+weight);
}
}
public void test(){
CowLeg c1=new CowLeg(123,"黑白色");
c1.info();
}
public static void main(String[] args){
Cow cow=new Cow(378.9);
cow.test();
}
}
当在非静态内部类的方法内访问某个变量时,系统优先在该方法内查找是否存在该名字的局部量,如果存在就使用该局部变量;如果不存在,则找到该方法所在的内部类中查找是否存在该名字的成员变量,如果存在则使用该变量,;如果不存在,则到该内部类所在的外部类中查找是否存在该名字的成员变量,如果存在,则使用该成员变量,如果已然不存在,则会出现系统错误:提示找不到该比变量。
因此,如果外部成员变量、内部类成员变量与内部类里方法的局部变量同名,则可通过使用this,外部类名.this作为限定类区分。
非静态类可以访问外部类的private成员变量,但反过来就不成立。非静态内部类的成员变量只在非静态内部类范围内是可知的,并不能被外部类直接使用。如果外部类需要访问非静态内部类的成员变量,则必须要显示的创建非静态内部类对象来调用访问其内部成员。
public class Outer {
private int outProp=9;
class Inner{
private int inProp=5;
public void acessOuterProp(){
//非静态内部类可以直接访问外部类的private成员变量
System.out.println("外部类的private值:"+outProp);
}
}
public void accessInnerProp(){
//外部类不能直接访问非静态内部类的实例变量
//下面代码出现编译错误
//System.out.println("内部类的prop值:"+inProp);
//如需访问内部类的实例变量,必须显示创建内部类对象
System.out.println("内部类inProp值:"+new Inner().inProp);
}
public static void main(String[] args){
Outer out=new Outer();
out.accessInnerProp();
}
}
非静态内部类对象和外部类对象的关系是怎样的?
非静态内部类对象必须寄生在的外部类对象里,而外部类对象则不必一定有非静态内部类对象寄生在其中。简单的说没如果存在一个非静态内部类对象,则一定存在一个被他寄生在外部类对象。但外部类对象存在时,外部类对象里不一定有内部类对象,。因此外部类对象访问非静态内部类成员时可能非静态内部类对象根本不存在,而非静态内部类对象访问外部类成员时,外部类对象一定存在。
为什么静态内部类的实例方法也不能访问外部类的实力属性呢?
因为静态内部类的是外部类的类相关的,而不是外部类对象相关的。也就是说,静态内部类对象不是寄生在外部类的实例中,而是寄生在外部类的类本身中,当静态内部类对象存在时,并不存在一个被他寄生的外部类对象,静态内部类对象只持有外部类的类引用,没有持有外部类对象的引用,如果允许静态内部类的实例方法访问外部类的实例成员,但找不到被寄生的外部对象,这将引起错误。
静态内部类是外部类的一个静态成员,因此外部类的所有方法、所有初始化快中可以使用静态内部类来定义变量、创建对象等。
外部类依然不能直接访问静态内部类的成员,但可以使用静态内部类的类名作为调用者来访问内部类的成员,也可以使用静态内部类对象作为调用者来访问静态内部类的实例成员。
public class AccessStaticInnerClass {
static class StaticInnerClass{
private static int prop1=5;
private static int prop2=9;
}
public void accessInnerProp(){
//System.out.println(prop1);
//应通过类名访问静态内部类的类成员
System.out.println("porp1的值为:"+StaticInnerClass.prop1);
//另一种形式
System.out.println("prop2的值为:"+new StaticInnerClass().prop2);
}
public static void main(String[] args){
AccessStaticInnerClass ASIC=new AccessStaticInnerClass();
ASIC.accessInnerProp();
}
}
除此之外,Java还允许在接口里定义内部类,接口里定义的内部类默认使用public static修饰,也就是说接口内部类只能是静态内部类。
如果为接口内部类指定访问控制符,则只能指定public访问控制符;如果定义接口内部类时省略访问控制符,则该内部类默认是public访问控制权限。
接口里能否定义内部接口?
可以,接口里的内部接口是接口的成员,因此系统默认添加public static两个修饰符,如果定义接口里的内部接口时指定访问控制符,则只能使用public。当然定义接口的内部接口意义不大,因为接口的作用是定义一个公共范围(暴露出来供大家使用),如果把这个接口定义成一个内部接口,那么就没有什么实际意义,在实际开发中很少看到这样的用法。
*1.在外部类以外使用非静态内部类
*省略访问控制符的内部类,只能被与外部类处于同一个包中的其他类访问
*使用protact修饰的内部类可被与外部类处于同一包中的其他类和外部类的子类访问
*使用public 修饰的内部类,可在任何地方被访问
在外部类以外的地方定义内部类(包括静态和非静态两种)变量
OuterClass.InnerClass varName
从上面的语法格式可以看出来,在外部类以外的地方使用内部类,内部类完整的类名应该是OuterClass.InnerClass。如果类有报名则应该添加包名前缀.
由于非静态内部类对象必须寄生在外部类的对象里,因此创建非静态内部类对象之前,必须先创建其外部类对象。在外部类对象以外的地方创建非静态内部类的语法如下:
OuterInstance.new InnerConstructor()
class Out{
//定义一个内部类,不使用访问控制符
//即只有一个包中的其他类可以访问该内部类
class In{
public In(String msg){
System.out.println(msg);
}
}
}
public class CeateInnerInstance {
public static void main(String[] args){
Out.In in=new Out().new In("测试信息");
//上面的代码可以改为以下这三行代码
//使用OutterClass.InnerClass的形式定义内部类变量
/*Out.In in;
* 创建外部类实例,非静态内部类实例将寄生在该实例中
* Out out=new Out();
* 通过外部类实例和new来调用内部类构造器创建非静态内部类实例
* in=out.new In("测试信息");
*/
}
}
下面程序定义了一个子类继承Out类的非静态内部类In类
public class SubClass extends Out.In {
public SubClass(Out out){
//通过传入out对象来显式地调用In构造器
out.super("hello");
}
}
代码中super代表调用In类的构造器,而Out则代表外部类对象(上面Out、In两个类直接来自于目前一个CreateInnerstance.java)
从上面的代码可以看出需要创建SubClass对象时必须要创建一个Out对象。这是合理的,因为SubClass是非静态的内部类In类的子类,非静态内部类In对象里必须有一个队Out对象的引用,其子类SubClass对象里也应该持有对Out对象的引用。当创建SubClass对象时传给构造器的Out对象,就是SubClass对象里Out对象引用所指向的对象。
*2.在外部类以外使用静态内部类
new OuterClass.InnerConstructor();
class StaticOut{
//定义一个静态内部类,不使用访问控制符
//即同一个包中的其他类可访问该类的内容
static class StaticIn{
public StaticIn(){
System.out.println("静态内部类的构造器");
}
}
}
public class CreateStaticInnerInstance{
public static void main(String[] args){
StaticOut.StaticIn in=new StaticOut.StaticIn();
/*
* 上面的代码可以改为如下两行代码
* 使用OuterClass.InnerClass的形式定义内部类变量
* StaticOut.StaticIn in;
* 通过new来调用内部类构造器创建静态内部类实例
* in=new StaticOut.StaticIn();
* */
}
}
相比较发现,使用静态内部类比使用非静态内部类要简单的多,只要把外部类当成静态内部类的包空间即可。因此当程序需要使用内部类时,应该首先考虑静态内部类方法。
*2.局部内部类
如果把一个内部类放在方法里定义,则这个内部类就是一个局部内部类局部内部类仅在该方法里有效
public class LocalInnerClass {
public static void main(String[] args){
//定义局部内部类
class InnerBase{
int a;
}
//定义局部内类的子类
class InnerSub extends InnerBase{
int b;
}
//创建有局部内部类的对象
InnerSub is=new InnerSub();
is.a=5;
is.b=8;
System.out.println("InnerBase类中a变量为:"+is.a+",InnerSub类中b变量的值为:"+is.b);
}
}