在Java中类可以是静态的么?
在Java中类可以是静态的。在Java中有静态实例变量,静态方法,以及静态块,类也可以是静态的。在Java中我们可以在类中再次定义一个类。这种类被称为嵌套类。嵌套类外围的类被称为外部类。在Java中不能使最顶层类为静态类,而只有嵌套的类可以是静态类。
静态类与非静态类的区别?
下面列出了静态类与非静态类的主要区别。非静态嵌套类通常被称为内部类。
嵌套静态类不需要外部类的引用,但是非静态嵌套类或者内部类需要外部类的引用。(Nested static class doesn’t need reference of Outer class, but Non-static nested class or Inner class requires Outer class reference.)内部类(非静态嵌套类)可以访问外部类的静态与非静态成员。静态类不能够访问外部类的非静态成员。创建内部类的实例,在没有外部类的实例时,无法创建。内部类可引用其所在外部类的数据与方法。因此我们不需要传递对象的引用给内部类的构造器。因为这一点,内部类使得程序变得更简洁。
[java]
view plain
copy
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]
view plain
copy
class Outer{ public static class StaticInner{ } public class Inner{ } public static void test(){ Inner it1 = new Inner(); // 报错,需要创建Outer,然后通过Outer建立Inner的实例 StaticInner st = new StaticInner(); } public void test2(){ Inner it2 = new Inner(); } }
嵌套类
在Java中,嵌套类是定义在另一个类内部的类。
使用嵌套类的目的是将外部类与嵌套类清晰地组织在一起,并表示这两个类是一起使用的。或者,嵌套类仅仅在内部被外围类所使用。
Java开发者通常将嵌套类视为内部类,但内部类(非静态嵌套类)仅仅是Java中几种不同嵌套类中的一种。
在Java中,嵌套类被看作是外围类的成员。这样,嵌套类可以用public,package(无访问修饰符),protected及private来修饰。因此,Java中的嵌套类可以被子类继承。
在Java中你可以创建几种不同类型的嵌套类。它们是:
静态嵌套类非静态嵌套类局部类匿名类
静态嵌套类 静态嵌套类是以如下形式声明的:
[java]
view plain
copy
public class Outer { public static class Nested { } }
为了创建嵌套类的实例,你必须以外部类Outer作为类Nested的前缀来引用它。Outer.Nested instance = new Outer.Nested();由于是静态的,静态嵌套类只能通过一个其外层类的实例的引用来访问外部类实例。
非静态嵌套类(内部类)
在java中非静态嵌套类被称为内部类。内部类是与一个外部类实例相关联。必须先创建外部类实例,随后才能创建内部类。
[java]
view plain
copy
public class Outer { public class Inner { } } Outer outer = new Outer(); Outer.Inner inner = outer.new Inner();
非静态嵌套类(内部类)能够访问外部类的域,即使它们被声明为private.
[java]
view plain
copy
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();
内部类作用域屏蔽
如果内部类声明的域或方法与外围类有相同的名字,内部域或方法会屏蔽外部类的域或方法。
[java]
view plain
copy
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.变量名 的形式来引用。
[java]
view plain
copy
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中局部类与内部类类似,局部类定义在一个方法或作用域块的内部。
[java]
view plain
copy
class Outer { public void printText() { class Local { } Local local = new Local(); } }
局部类只能在定义的作用域内被访问。 局部类可以像内部类一样访问外围类的方法或变量。 局部类可以访问其所在方法或作用域块内部的变量,这些变量需要被定义为finnal。 从Java8开始,局部类可以访问其所在方法的局部变量以及方法参数。这些参数必须被声明为final或是effectually final, effectually final意思是,变量在初始化后再不会被改变。方法参数一般都是 effectually final. 局部类也可以在静态方法中声明。这种情况,局部类仅仅可以访问外围类的静态部分。局部类不能包含静态声明(常量可以 - 变量被声明为static final),因为本质上,即使局部类在静态方法中被声明,局部类也是非静态的。 局部类与内部类有着相同的变量屏蔽规则。
匿名类
Java中,如果嵌套类没有名称,则为匿名类。通常作为一个已经存在的类的子类来声明,或是某个接口的实现。匿名类在实例化时定义。如下定义了一个SuperClass的匿名子类。
[java]
view plain
copy
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()方法。 匿名类可以实现一个接口,而不需要继承一个类。
[java]
view plain
copy
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的实现:
[java]
view plain
copy
public class Cache { private Map cacheMap = new HashMap(); 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 cacheMap = new HashMap(); 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。