Java中的嵌套类(nested Class)内部类(inner Class)匿名类(Anonymous Class)

在Java中类可以是静态的么?

在Java中类可以是静态的。在Java中有静态实例变量,静态方法,以及静态块,类也可以是静态的。在Java中我们可以在类中再次定义一个类。这种类被称为嵌套类。嵌套类外围的类被称为外部类。在Java中不能使最顶层类为静态类,而只有嵌套的类可以是静态类

静态类与非静态类的区别?

下面列出了静态类与非静态类的主要区别。非静态嵌套类通常被称为内部类。

  1. 嵌套静态类不需要外部类对象的引用,但是非静态嵌套类(内部类)需要外部类对象的引用。(Nested static class doesn’t need reference of Outer class, but Non-static nested class or Inner class requires Outer class reference.)
  2. 内部类(非静态嵌套类)可以访问外部类的静态与非静态成员。静态嵌套类 不能够访问外部类的非静态成员。
  3. 创建内部类的实例,在没有外部类的实例时,无法创建。内部类可引用其所在外部类的数据与方法。因此我们不需要传递对象的引用给内部类的构造器。因为这一点,内部类使得程序变得更简洁。
class OuterClass{
	private static String msg = "GeeksForGeeks";
	private String nonStaticMsg = "nonStaticGeeksForGeeks";
	// 静态嵌套类
	public static class NestedStaticClass{
		// 只有外部类的静态称为可以在该静态类中访问
		public void printMessage(){
			System.out.println("Message from nested static class: " + msg);
			// 报错,因为在静态类中访问非静态成员nonStaticMsg
//			System.out.println("Message from nested static class: " + nonStaticMsg);
			
		}
	}
	
	public class InnerClass{
		public void display(){
			// 内部类中,静态与非静态成员都可以访问。
			System.out.println("Message from nested static class: " + msg);
			System.out.println("Message from nested static class: " + nonStaticMsg);
		}
	}
}
 
public class App 
{
    public static void main( String[] args )
    {
    	// 创建嵌套静态类的实例
    	OuterClass.NestedStaticClass printer = new OuterClass.NestedStaticClass();
    	printer.printMessage();
    	
    	// 为了创建内部类的实例,我们需要一个外部类的实例
    	OuterClass outer = new OuterClass();
    	OuterClass.InnerClass inner = outer.new InnerClass();
    	// 调用内部类的非静态方法
    	inner.display();
    	
    	// 还可以用以一步来创建内部类的实例
    	OuterClass.InnerClass innerObject = new OuterClass().new InnerClass();
    	innerObject.display();
    }
    
}

嵌套类

在Java中,嵌套类是定义在另一个类内部的类。

使用嵌套类的目的是将外部类与嵌套类清晰地组织在一起,并表示这两个类是一起使用的。或者,嵌套类仅仅在内部被外围类所使用。
Java开发者通常将嵌套类视为内部类,但内部类(非静态嵌套类)仅仅是Java中几种不同嵌套类中的一种。
在Java中,嵌套类被看作是外围类的成员。这样,嵌套类可以用public,package(无访问修饰符),protected及private来修饰。因此,Java中的嵌套类可以被子类继承。

在Java中你可以创建几种不同类型的嵌套类。它们是:

  • 静态嵌套类
  • 非静态嵌套类 内部类
  • 局部类  :Java中局部类与内部类类似,局部类定义在一个方法或作用域块的内部。
  • 匿名类

静态嵌套类

静态嵌套类是以如下形式声明的:

public class Outer {
 
  public static class Nested {
 
  }
 
}

为了创建嵌套类的实例,你必须以外部类Outer作为类Nested的前缀来引用它。Outer.Nested instance = new Outer.Nested();由于是静态的,静态嵌套类只能通过一个其外层类的实例的引用来访问外部类实例

 

非静态嵌套类(内部类)

在java中非静态嵌套类被称为内部类。内部类是与一个外部类实例相关联。必须先创建外部类实例,随后才能创建内部类。

public class Outer {
 
  public class Inner {
  }
 
}
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();


非静态嵌套类(内部类)能够访问外部类的域,即使它们被声明为private.

public class Outer {
 
    private String text = "I am private!";
 
    public class Inner {
 
        public void printText() {
            System.out.println(text);
        }
    }
}
//printText中引用了一个Outer类中private成员text.这是可以的。下面是printText的调用方式。
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.printText();

 


内部类作用域屏蔽

如果内部类声明的域或方法与外围类有相同的名字,内部域或方法会屏蔽外部类的域或方法。

public class Outer {
 
    private String text = "I am Outer private!";
 
    public class Inner {
 
        private String text = "I am Inner private";
 
        public void printText() {
            System.out.println(text);
        }
    }
}

上面的例子中,Outer与Inner类都包含有名为text的域。当Inner类引用text时,它引用的是自己的text域。外部类引用text时,它引用的也是自己的text域。

 

Java中,内部类可以引用外部类同名的text域。通过,外部类名.this.变量名 的形式来引用。

public class Outer {
 
    private String text = "I am Outer private!";
 
    public class Inner {
 
        private String text = "I am Inner private";
 
        public void printText() {
            System.out.println(text);
            System.out.println(Outer.this.text);
        }
    }
}


局部类

Java中局部类与内部类类似,局部类定义在一个方法或作用域块的内部。

class Outer {
 
    public void printText() {
 
        class Local {
 
        }
 
        Local local = new Local();
    }
 
}


局部类只能在定义的作用域内被访问。

局部类可以像内部类一样访问外围类的方法或变量。

局部类可以访问其所在方法或作用域块内部的变量,这些变量需要被定义为finnal

从Java8开始,局部类可以访问其所在方法的局部变量以及方法参数。这些参数必须被声明为final或是effectually final, effectually final意思是,变量在初始化后再不会被改变。方法参数一般都是 effectually final.
 

局部类也可以在静态方法中声明。这种情况,局部类仅仅可以访问外围类的静态部分。局部类不能包含静态声明(常量可以 - 变量被声明为static final),因为本质上,即使局部类在静态方法中被声明,局部类也是非静态的。


局部类与内部类有着相同的变量屏蔽规则。

 

匿名类

Java中,如果嵌套类没有名称,则为匿名类。通常作为一个已经存在的类的子类来声明,或是某个接口的实现。匿名类在实例化时定义。如下定义了一个SuperClass的匿名子类。

public class SuperClass {
 
  public void doIt() {
    System.out.println("SuperClass doIt()");
  }
 
}
SuperClass instance = new SuperClass() {
 
    public void doIt() {
        System.out.println("Anonymous class doIt()");
    }
};
 
instance.doIt();


匿名类子类化SuperClass并且覆盖doIt()方法。

匿名类可以实现一个接口,而不需要继承一个类。

public interface MyInterface {
 
  public void doIt();
 
}
MyInterface instance = new MyInterface() {
 
    public void doIt() {
        System.out.println("Anonymous class doIt()");
    }
};
 
instance.doIt();

如你所见,匿名类实现了一个接口与匿名类继承另一个类十分类似。

匿名类可以访问外围类的成员,它也可以访问被声明为final 或 effectively final(since Java8)的局部变量。

你可以在匿名类中声明一个变量或方法,但不能声明一个构造器,你可以声明一个静态初始化器取代构造器。例如:final Strint textToPrint = "Text...";

匿名类与内部类有着同样的作用域屏蔽规则。

 

嵌套类的好处

嵌套类的好处是,你可以将相关的类组织在一起。你可以将相关类放入一个包中,但将一个类放入另一个类内部,以加强它们之间的关联。

嵌套类通过仅仅被外围类所使用。通常嵌套类仅仅对外围类可见,仅仅是内部使用,而在对于外围类之外的类是不可见的。其它情况下,仅当外围类被使用时,嵌套类才对于外围类之外的类可见。

一个实例是,Cache类。在Cache类内部,你声明了一个CacheEntry类,这个类包含了关于Cache的信息。(信息包括:值,插入时间,访问次数等)。 如果用户不需要获取CacheEntry自身信息,Cache类的使用者是看不到CacheEntry类的,仅能看到缓存的值。然而,Cache类可能会使cacheEntry类对外部可见。这样使用者可以获得更多的信息,而不仅仅是存数的值。
 

如下是两个Cache的实现:

public class Cache {
 
    private Map<String, CacheEntry> cacheMap = new HashMap<String, CacheEntry>();
 
    private class CacheEntry {
        public long   timeInserted = 0;
        public object value        = null;
    }
 
    public void store(String key, Object value){
        CacheEntry entry = new CacheEntry();
        entry.value = value;
        entry.timeInserted = System.currentTimeMillis();
        this.cacheMap.put(key, entry);
    }
 
    public Object get(String key) {
        CacheEntry entry = this.cacheMap.get(key);
        if(entry == null) return null;
        return entry.value;
    }
 
}
 
 
public class Cache {
 
    private Map<String, CacheEntry> cacheMap = new HashMap<String, CacheEntry>();
 
    public class CacheEntry {
        public long   timeInserted = 0;
        public object value        = null;
    }
 
    public void store(String key, Object value){
        CacheEntry entry = new CacheEntry();
        entry.value = value;
        entry.timeInserted = System.currentTimeMillis();
        this.cacheMap.put(key, entry);
    }
 
    public Object get(String key) {
        CacheEntry entry = this.cacheMap.get(key);
        if(entry == null) return null;
        return entry.value;
    }
 
    public CacheEntry getCacheEntry(String key) {
        return this.cacheMap.get(key);
        }
 
}


第一个类 隐藏了CacheEntry嵌套类

第二个类 则可以获取CacheEntry

#####################################################################################################################################################################

静态类(Static class)

嵌套类(nested Class) 静态嵌套类 和 非静态嵌套类(内部类)

内部类(inner Class)   非静态嵌套类通常被称为内部类。

匿名类(Anonymous Class)   匿名类与内部类有着同样的作用域屏蔽规则。

 

内部类(inner Class)

它可以不依赖于外部类实例而被实例化。而通常的内部类需要在外部类实例化后才能被实例化,其语法看起来挺诡异的,如下所示。

package com.dapeng.learning.classtype;

/**
 * 扑克类(一副扑克)
 */
public class Poker_InnerClass {
    private static String[] suites = {"黑桃", "红桃", "草花", "方块"};
    private static int[] faces = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
    private Card[] cards;
 
    /**
     * 构造器
     */
    public Poker_InnerClass() {
        cards = new Card[52];
        for(int i = 0; i < suites.length; i++) {
            for(int j = 0; j < faces.length; j++) {
                cards[i * 13 + j] = new Card(suites[i], faces[j]);
            }
        }
    }
 
    /**
     * 洗牌(随机乱序)
     */
    public void shuffle() {
        for(int i = 0, len = cards.length; i < len; i++) {
            int index = (int) (Math.random() * len);
            Card temp = cards[index];
            cards[index] = cards[i];
            cards[i] = temp;
        }
    }
 
    /**
     * 发牌
     * @param index 发牌的位置
     */
    public Card deal(int index) {
        return cards[index];
    }
 
    /**
     * 卡片类(一张扑克)
     * [静态嵌套类]
     */
    public static class CardStatic {
        private String suite;   // 花色
        private int face;       // 点数
 
        public CardStatic(String suite, int face) {
            this.suite = suite;
            this.face = face;
        }
 
        @Override
        public String toString() {
            String faceStr = "";
            switch(face) {
            case 1: faceStr = "A"; break;
            case 11: faceStr = "J"; break;
            case 12: faceStr = "Q"; break;
            case 13: faceStr = "K"; break;
            default: faceStr = String.valueOf(face);
            }
            return suite + faceStr;
        }
    }

    /**
     * 卡片类(一张扑克)
     * [非静态嵌套 也称 内部类]
     */
    public class Card {
        private String suite;   // 花色
        private int face;       // 点数

        public Card(String suite, int face) {
            this.suite = suite;
            this.face = face;
        }

        @Override
        public String toString() {
            String faceStr = "";
            switch(face) {
                case 1: faceStr = "A"; break;
                case 11: faceStr = "J"; break;
                case 12: faceStr = "Q"; break;
                case 13: faceStr = "K"; break;
                default: faceStr = String.valueOf(face);
            }
            return suite + faceStr;
        }
    }
}

执行代码

package com.dapeng.learning.classtype;

import org.junit.jupiter.api.Test;

public class InnerClassTest {

    @Test
    void testInnerClass()
    {
        Poker_InnerClass poker = new Poker_InnerClass();
        poker.shuffle();                // 洗牌
        Poker_InnerClass.Card c1 = poker.deal( 0 );  // 发第一张牌

        // 对于非静态嵌套类(内部类)Card,只有通过其外部类Poker_InnerClass对象才能创建Card对象
        //@todo 非静态内部类【正常内部类不对外直接实例化】
        Poker_InnerClass.Card c2 = poker.new Card( "红心", 1 );    // 自己创建一张牌
        System.out.println(c1);     // 洗牌后的第一张
        System.out.println(c2);     // 打印: 红心A

        //@todo 静态嵌套类【正常内部类不对外直接实例化】
        Poker_InnerClass.CardStatic c3 = new Poker_InnerClass.CardStatic( "红心", 100 );
        System.out.println( c3 );

    }

}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值