Java中的静态嵌套类,为什么?
我正在查看Java中的静态嵌套类,为什么?,java,class,static,member,Java,Class,Static,Member,我正在查看LinkedList的Java代码,注意到它使用了一个静态嵌套类Entry public class LinkedList<E> ... { ... private static class Entry<E> { ... } } 公共类链接列表。。。{ ... 私有静态类条目{…} } 使用静态嵌套类而不是普通内部类的原因是什么 我能想到的唯一原因是,条目不能访问实例变量,所以从OOP的角度来看,它具有更好的封装性 但我想可能还有其他原因,也许是性能。
LinkedList
的Java代码,注意到它使用了一个静态嵌套类Entry
public class LinkedList<E> ... {
...
private static class Entry<E> { ... }
}
公共类链接列表。。。{
...
私有静态类条目{…}
}
使用静态嵌套类而不是普通内部类的原因是什么
我能想到的唯一原因是,条目不能访问实例变量,所以从OOP的角度来看,它具有更好的封装性
但我想可能还有其他原因,也许是性能。可能是什么
注意。我希望我的术语是正确的,我会称之为静态内部类,但我认为这是错误的:在我看来,问题应该是相反的,每当你看到一个内部类-它真的需要是一个内部类,具有额外的复杂性和隐式(而不是显式和清晰,依我看)对包含类的实例的引用
请注意,我有偏见,因为C#fan-C#没有内部类的等价物,尽管它有嵌套类型。我不能说我已经错过了内部类:)静态与普通的原因之一与类加载有关。不能在其父类的构造函数中实例化内部类
PS:我一直认为“嵌套”和“内部”是可以互换的。术语中可能有细微的差别,但大多数Java开发人员都会理解。我不知道性能差异,但正如您所说,静态嵌套类不是封闭类实例的一部分。创建静态嵌套类似乎更简单,除非您确实需要它是一个内部类
这有点像为什么我总是让我的变量在Java中成为最终变量——如果它们不是最终变量,我知道它们有一些有趣的地方。如果使用内部类而不是静态嵌套类,应该有一个很好的理由。您链接到的Sun页面在这两者之间有一些关键区别: 嵌套类是其封闭类的成员。非静态嵌套类(内部类)可以访问封闭类的其他成员,即使它们被声明为私有。静态嵌套类无权访问封闭类的其他成员。
注意:静态嵌套类与其外部类(和其他类)的实例成员进行交互,就像任何其他顶级类一样实际上,静态嵌套类在行为上是一个顶级类,为了便于打包,它嵌套在另一个顶级类中。
class OuterClass {
private OuterClass(int x) {
System.out.println("x: " + x);
}
static class InnerClass {
public static void test() {
OuterClass outer = new OuterClass(1);
}
}
}
public class Test {
public static void main(String[] args) {
OuterClass.InnerClass.test();
// OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
}
}
不需要将LinkedList.Entry
作为顶级类,因为它仅由LinkedList
使用(还有一些其他接口也具有名为Entry
的静态嵌套类,例如Map.Entry
-相同的概念)。而且因为它不需要访问LinkedList的成员,所以它是静态的,这是一种更干净的方法
因此,我认为如果您使用的是嵌套类,最好是从它是静态的开始,然后根据您的使用情况决定它是否真的需要是非静态的。首先,非静态的内部类有一个额外的隐藏字段,指向外部类的实例。因此,如果Entry类不是静态的,那么除了具有它不需要的访问权限之外,它还将携带四个指针,而不是三个指针
作为一个规则,我会说,如果你定义了一个类,它基本上是作为数据成员的集合,比如C中的“Stutt”,考虑使它静态。
< P>简单的例子:package test;
public class UpperClass {
public static class StaticInnerClass {}
public class InnerClass {}
public static void main(String[] args) {
// works
StaticInnerClass stat = new StaticInnerClass();
// doesn't compile
InnerClass inner = new InnerClass();
}
}
如果非静态类不能在上层类的实例中实例化exept(因此在main是静态函数的示例中不是这样)这里需要考虑非明显的内存保留问题。由于非静态内部类维护对其“外部”类的隐式引用,因此如果内部类的实例被强引用,则外部实例也被强引用。当外部类未被垃圾收集时,这可能会导致一些令人头疼的问题,即使看起来没有任何东西引用它。非静态内部类可能会导致内存泄漏,而静态内部类将对此进行保护。如果外部类包含大量数据,则会降低应用程序的性能。来自: 如果需要访问,请使用非静态嵌套类(或内部类) 到封闭实例的非公共字段和方法。使用静电计 嵌套类(如果不需要此访问)
静态嵌套类与任何其他外部类一样,因为它无权访问外部类成员 为了便于打包,我们可以将静态嵌套类合并到一个外部类中以实现可读性。除此之外,静态嵌套类没有其他用例 关于这种用法的示例,您可以在Android R.java(参考资料)文件中找到。 android的Res文件夹包含布局(包含屏幕设计)、drawable文件夹(包含用于项目的图像)、values文件夹(包含字符串常量)等 由于所有文件夹都是Res文件夹的一部分,android工具生成一个R.java(resources)文件,该文件在内部为每个内部文件夹包含许多静态嵌套类 以下是android中生成的R.java文件的外观: 在这里,它们仅用于包装方便
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.techpalle.b17_testthird;
public final class R {
public static final class drawable {
public static final int ic_launcher=0x7f020000;
}
public static final class layout {
public static final int activity_main=0x7f030000;
}
public static final class menu {
public static final int main=0x7f070000;
}
public static final class string {
public static final int action_settings=0x7f050001;
public static final int app_name=0x7f050000;
public static final int hello_world=0x7f050002;
}
}
内阶级优势--
class car{
class wheel{
}
}
内部类有四种类型
public class Student {
public static final Comparator<Student> BY_NAME = new ByName();
private final String name;
...
private static class ByName implements Comparator<Student> {
public int compare() {...}
}
}
class OuterClass {
private OuterClass(int x) {
System.out.println("x: " + x);
}
static class InnerClass {
public static void test() {
OuterClass outer = new OuterClass(1);
}
}
}
public class Test {
public static void main(String[] args) {
OuterClass.InnerClass.test();
// OuterClass outer = new OuterClass(1); // It is not possible to create outer instance from outside.
}
}
public class Message {
private MessageType messageType; // component of parent class
public enum MessageType {
SENT, RECEIVE;
}
}
class Otherclass {
public boolean isSent(Message message) {
if (message.getMessageType() == MessageType.SENT) { // accessible at other places as well
return true;
}
return false;
}
}
public class Message {
private Content content; // Component of message class
private static class Content { // can only be a component of message class
private String body;
private int sentBy;
public String getBody() {
return body;
}
public int getSentBy() {
return sentBy;
}
}
}
class Message2 {
private Message.Content content; // Not possible
}