Java中内部类和静态嵌套类的主要区别是什么?设计/实现是否在选择其中一个方面发挥作用?
当前回答
嵌套类的另一个用例,除了已经提到的那些用例之外,是当嵌套类具有只能从外部类访问的方法时。这是可能的,因为外部类可以访问嵌套类的私有构造函数、字段和方法。
在下面的示例中,银行可以发行具有私有构造函数的Bank.CreditCard,并可以使用Bank.credit card的私有setLimit(…)实例方法根据当前银行策略更改信用卡的限额。从任何其他类只能访问Bank.CreditCard的公共方法。
public class Bank {
// maximum limit as per current bank policy
// is subject to change
private int maxLimit = 7000;
// ------- PUBLIC METHODS ---------
public CreditCard issueCard(
final String firstName,
final String lastName
) {
final String number = this.generateNumber();
final int expiryDate = this.generateExpiryDate();
final int CVV = this.generateCVV();
return new CreditCard(firstName, lastName, number, expiryDate, CVV);
}
public boolean setLimit(
final CreditCard creditCard,
final int limit
) {
if (limit <= this.maxLimit) { // check against current bank policy limit
creditCard.setLimit(limit); // access private method Bank.CreditCard.setLimit(int)
return true;
}
return false;
}
// ------- PRIVATE METHODS ---------
private String generateNumber() {
return "1234-5678-9101-1123"; // the numbers should be unique for each card
}
private int generateExpiryDate() {
return 202405; // date is YYYY=2024, MM=05
}
private int generateCVV() {
return 123; // is in real-life less predictable
}
// ------- PUBLIC STATIC NESTED CLASS ---------
public static final class CreditCard {
private final String firstName;
private final String lastName;
private final String number;
private final int expiryDate;
private final int CVV;
private int balance;
private int limit = 100; // default limit
// the constructor is final but is accessible from outer class
private CreditCard(
final String firstName,
final String lastName,
final String number,
final int expiryDate,
final int CVV
) {
this.firstName = firstName;
this.lastName = lastName;
this.number = number;
this.expiryDate = expiryDate;
this.CVV = CVV;
}
// ------- PUBLIC METHODS ---------
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
public String getNumber() {
return this.number;
}
public int getExpiryDate() {
return this.expiryDate;
}
// returns true if financial transaction is successful
// otherwise false
public boolean charge(final int amount) {
final int newBalance = this.balance - amount;
if (newBalance < -this.limit) {
return false;
}
this.balance = newBalance;
return true;
}
// ------- PRIVATE METHODS ---------
private int getCVV() {
return this.CVV;
}
private int getBalance() {
return this.balance;
}
private void setBalance(final int balance) {
this.balance = balance;
}
private int getLimit() {
return limit;
}
private void setLimit(final int limit) {
this.limit = limit;
}
}
}
其他回答
内部类的实例是在创建外部类的实例时创建的。因此,内部类的成员和方法可以访问外部类的实例(对象)的成员和对象。当外部类的实例超出范围时,内部类实例也将停止存在。
静态嵌套类没有具体实例。它只是在第一次使用时加载的(就像静态方法一样)。它是一个完全独立的实体,其方法和变量不能访问外部类的实例。
静态嵌套类不与外部对象耦合,它们速度更快,并且不占用堆/堆栈内存,因为不需要创建此类的实例。因此,经验法则是尽量使用有限的范围(private>=class>=protected>=public)定义静态嵌套类,然后将其转换为内部类(通过删除“static”标识符),如果确实有必要,则放宽范围。
嵌套类是一个非常通用的术语:每个不是顶级的类都是嵌套类。内部类是非静态嵌套类。约瑟夫·达西写了一篇关于嵌套、内部、成员和顶级课程的非常好的解释。
针对Java和/或嵌套类新手的学习者
嵌套类可以是:1.静态嵌套类。2.非静态嵌套类。(也称为内部类)=>请记住这一点
1.内部类例子:
class OuterClass {
/* some code here...*/
class InnerClass { }
/* some code here...*/
}
内部类是嵌套类的子集:
内部类是特定类型的嵌套类内部类是嵌套类的子集可以说内部类也是嵌套类,但不能说嵌套类也是内部类。
内层专业:
内部类的实例可以访问外部类的所有成员,即使是标记为“private”的成员
2.静态嵌套类:例子:
class EnclosingClass {
static class Nested {
void someMethod() { System.out.println("hello SO"); }
}
}
案例1:从非封闭类实例化静态嵌套类
class NonEnclosingClass {
public static void main(String[] args) {
/*instantiate the Nested class that is a static
member of the EnclosingClass class:
*/
EnclosingClass.Nested n = new EnclosingClass.Nested();
n.someMethod(); //prints out "hello"
}
}
案例2:从封闭类实例化静态嵌套类
class EnclosingClass {
static class Nested {
void anotherMethod() { System.out.println("hi again"); }
}
public static void main(String[] args) {
//access enclosed class:
Nested n = new Nested();
n.anotherMethod(); //prints out "hi again"
}
}
静态类专业:
静态内部类只能访问外部类的静态成员,不能访问非静态成员。
结论:问:Java中内部类和静态嵌套类的主要区别是什么?答:只需仔细阅读上面提到的每门课的细节。
我认为这里没有什么要补充的,大多数答案完美地解释了静态嵌套类和内部类之间的区别。但是,当使用嵌套类与内部类时,请考虑以下问题。正如在两个答案中提到的,如果没有封闭类的实例,内部类就无法实例化,这意味着它们持有指向封闭类实例的指针,这可能导致内存溢出或堆栈溢出异常,因为即使不再使用封闭类,GC也无法对其进行垃圾收集。要明确这一点,请检查以下代码:
public class Outer {
public class Inner {
}
public Inner inner(){
return new Inner();
}
@Override
protected void finalize() throws Throwable {
// as you know finalize is called by the garbage collector due to destroying an object instance
System.out.println("I am destroyed !");
}
}
public static void main(String arg[]) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
// out instance is no more used and should be garbage collected !!!
// However this will not happen as inner instance is still alive i.e used, not null !
// and outer will be kept in memory until inner is destroyed
outer = null;
//
// inner = null;
//kick out garbage collector
System.gc();
}
如果删除//inner=null;该计划将付诸实施“我被摧毁了!”,但保持评论不会。原因是白色内部实例仍然被引用,GC无法收集它,并且因为它引用(具有指向)外部实例,所以它也没有被收集。项目中有足够的这些对象,可能会耗尽内存。与静态内部类相比,静态内部类不指向内部类实例,因为它与实例无关,而是与类相关。如果将Inner类设置为静态并使用Outer.Inner I=newOuter.Innr()实例化,则上述程序可以打印“我被摧毁了!”;
我认为,通常遵循的惯例是:
顶级类中的静态类是嵌套类顶级类中的非静态类是内部类还有两种形式:本地类-在块(如方法或构造函数体)内部声明的类匿名类-在表达式和语句中创建实例的未命名类
然而,需要记住的其他几点是:
顶级类和静态嵌套类在语义上是相同的,只是在静态嵌套类的情况下,它可以对其外部〔父〕类的私有静态字段/方法进行静态引用,反之亦然。内部类可以访问外部[父]类的封闭实例的实例变量。然而,并不是所有的内部类都有封闭实例,例如静态上下文中的内部类,比如静态初始值设定项块中使用的匿名类。默认情况下,匿名类扩展父类或实现父接口,并且没有进一步的子句来扩展任何其他类或实现任何其他接口。所以新建YourClass(){};意味着类〔Anonymous〕扩展了YourClass{}新建YourInterface(){};表示类〔Anonymous〕实现YourInterface{}
我觉得还有一个更大的问题,那就是什么时候使用?这主要取决于你正在处理的场景,但阅读@jrudolph给出的回复可能会帮助你做出一些决定。
推荐文章
- 在流中使用Java 8 foreach循环移动到下一项
- 访问限制:'Application'类型不是API(必需库rt.jar的限制)
- 用Java计算两个日期之间的天数
- 如何配置slf4j-simple
- 在Jar文件中运行类
- 带参数的可运行?
- 我如何得到一个字符串的前n个字符而不检查大小或出界?
- 我可以在Java中设置enum起始值吗?
- Java中的回调函数
- c#和Java中的泛型有什么不同?和模板在c++ ?
- 在Java中,流相对于循环的优势是什么?
- Jersey在未找到InjectionManagerFactory时停止工作
- 在Java流是peek真的只是调试?
- Recyclerview不调用onCreateViewHolder
- 将JSON字符串转换为HashMap