标签:alc 逻辑 nts blank 场景 ade 错误 getc 内部类
鄙人最近尝试着翻译了自己的第一篇英文技术文档。
Java Nested Classes Reference From Oracle Documentation
在Java中我们可以在一个类的内部,再定义另外一个类,其中里面的那个类被称为嵌套类,示例如下。
class OuterClass { ... class NestedClass { ... } }
术语:嵌套类有两种类型:静态和非静态,当嵌套类被static修饰时,被称为静态嵌套类(static nested classes),没有被static修饰时的嵌套类被称作内部类(inner classes)
class OuterClass { ... static class StaticNestedClass { ... } class InnerClass { ... } }
嵌套类是外部基类(即外部类)的成员,非静态嵌套类(内部类)可以获取到外围基类的其他成员,其中也包括被声明为private的成员。静态嵌套类则不可以获取基类的其他成员。当做为作为外部类的成员,嵌套类可以被定义为private,public,protected或者package private。如果我们需要在其他外部类中使用内部类,则一定要将嵌套类声明为public或者 package private。
使用嵌套类有以下几个明显的优势:
静态嵌套类不能直接引用外部基类的实例变量和实例方法,对于这样的实例变量仅可以通过对象引用来获取。
通过使用外围基类名称来获取静态嵌套类
OuterClass.StaticNestedClass
如果我们想创建一个静态嵌套类的对象,则可以使用如下的方式
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
内部类可以通过外部类实例,直接获取基类对象的变量和方法,同理因为内部类是通过实例引用来和外部类建立关系的,所以在内部类中不能定义任何的静态成员。只有当外部类实例对象被创建出来之后,才可以实例化内部类。
class OuterClass { ... class InnerClass { ... } }
内部类实例只能存在于外部类实例中,并且可以直接访问其外部类实例的方法和字段。
在实例化内部类前,要先实例化外部类实例。可以通过如下方式,通过外部对象实例来创建内部类对象。
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
内部类有两种类型:局部类(local classes) 和 匿名类(anonymous classes).
局部类是一种被定义在代码块中的类,局部类通常时定义在方法体中。
可以在任何一个方法之中定义一个局部类,如for循环中,或者在if子句中。
下面的LocalClassExample,是用来验证两个手机号,在这个类的validatePhoneNumber方法中,定义了一个名为PhoneNumber的局部类。
public class LocalClassExample { static String regularExpression = "[^0-9]"; public static void validatePhoneNumber( String phoneNumber1, String phoneNumber2) { final int numberLength = 10; // Valid in JDK 8 and later: // int numberLength = 10; class PhoneNumber { String formattedPhoneNumber = null; PhoneNumber(String phoneNumber){ // numberLength = 7; String currentNumber = phoneNumber.replaceAll( regularExpression, ""); if (currentNumber.length() == numberLength) formattedPhoneNumber = currentNumber; else formattedPhoneNumber = null; } public String getNumber() { return formattedPhoneNumber; } // Valid in JDK 8 and later: // public void printOriginalNumbers() { // System.out.println("Original numbers are " + phoneNumber1 + // " and " + phoneNumber2); // } } PhoneNumber myNumber1 = new PhoneNumber(phoneNumber1); PhoneNumber myNumber2 = new PhoneNumber(phoneNumber2); // Valid in JDK 8 and later: // myNumber1.printOriginalNumbers(); if (myNumber1.getNumber() == null) System.out.println("First number is invalid"); else System.out.println("First number is " + myNumber1.getNumber()); if (myNumber2.getNumber() == null) System.out.println("Second number is invalid"); else System.out.println("Second number is " + myNumber2.getNumber()); } public static void main(String... args) { validatePhoneNumber("123-456-7890", "456-7890"); } }
通过删除原有手机号中除0-9之外的字符后,检查新的字符串中是否有十个数字,输出结果如下:
First number is 1234567890 Second number is invalid
局部类可以获取外部类的成员信息,在上一个例子中,PhoneNumber局部类的构造方法里通过LocalClassExample.regularExpression,就拿到了外部类中的regularExpression成员。
另外,局部类中也能使用局部变量,但是在局部类中只能使用被final修饰后的变量,当一个局部类要使用定义在外部代码块中的局部变量或者参数时,他会俘获(这个变量就是他的了)这个变量或者参数。
比如,PhoneNumber的构造方法中,能够/会,俘获numberLength,因为这个变量在外围块中被声明为final,这样的话numberLength 就成为了一个被俘获的变量了,有了主人。
但是在java 1.8版本中局部类能够使用定义在外部块中的final或者effectively final的变量或者参数,如果一个变量或者参数的值在初始化后便不会被改变,则被称为effectively final。
比如在下面的代码中,变量numberLength没有被显示的声明为final,在初始化后有在方法中又将numberLength的值修改为7:
PhoneNumber(String phoneNumber) { numberLength = 7; String currentNumber = phoneNumber.replaceAll( regularExpression, ""); if (currentNumber.length() == numberLength) formattedPhoneNumber = currentNumber; else formattedPhoneNumber = null; }
因为这个赋值语句numberLength = 7,变量numberLength 便不再是 effectively final了,在这种情形下,内部类尝试在if (currentNumber.length() == numberLength)
这行代码中获取numberLength时,编译器时会提示"local variables referenced from an inner class must be final or effectively final"
。
在java8中,如果在方法中声明了局部类,那么可以在局部类中拿到方法的入参,就像下面的方法:
public void printOriginalNumbers() { System.out.println("Original numbers are " + phoneNumber1 + " and " + phoneNumber2); }
局部类中的printOriginalNumbers方法获取到了方法validatePhoneNumber中的phoneNumber1 和phoneNumber2两个参数变量。
局部类像内部类一样,二者都不能定义和声明静态成员,在静态方法validatePhoneNumber中定义的PhoneNumber局部类,只能引用外部类中的静态成员。
如果将变量regularExpression定义为非静态,那么在java编译器编译的时候会提示"non-static variable regularExpression cannot be referenced from a static context."错误信息。
因为要获取外围代码块中的实例成员,所以局部类不能时静态的,所以在局部类中不能包含有静态声明。
不能在代码块中,尝试定义或者声明接口,因为接口本质上就是静态的,比如下面的代码是不能编译成功的,因为在greetInEnglish方法内部包含有HelloThere接口:
public void greetInEnglish() { interface HelloThere { public void greet(); } class EnglishHelloThere implements HelloThere { public void greet() { System.out.println("Hello " + name); } } HelloThere myGreeting = new EnglishHelloThere(); myGreeting.greet(); }
当然在局部类中也不能声明静态方法,下面的代码同样,在编译时会报"modifier ‘static‘ is only allowed in constant variable declaration"
,因为EnglishGoodbye.sayGoodbye这个方法被声明为静态方法了。
public void sayGoodbyeInEnglish() { class EnglishGoodbye { public static void sayGoodbye() { System.out.println("Bye bye"); } } EnglishGoodbye.sayGoodbye(); }
局部类中只有变量时常量的时候,才可能会出现有静态成员变量的情况,下面的代码中有静态成员但也可以编译通过,因为静态变量EnglishGoodbye.farewell是常量。
public void sayGoodbyeInEnglish() { class EnglishGoodbye { public static final String farewell = "Bye bye"; public void sayGoodbye() { System.out.println(farewell); } } EnglishGoodbye myEnglishGoodbye = new EnglishGoodbye(); myEnglishGoodbye.sayGoodbye(); }
匿名类可以使你的代码看上去更加的精简,可以在声明一个匿名类的同时对它进行初始化,除了没有类名以外,它跟局部类很像,对于只会使用一次的局部类的场景我们可以用匿名类来代替。
局部类就是一个类,而匿名类则更像是一个表达式,那么我们便可以在另外的表达式中使用匿名类。
下面的例子中 HelloWorldAnonymousClasses通过使用匿名类创建局部变量frenchGreeting 和spanishGreeting,通过使用局部类来创建和初始化englishGreeting。
Java Nested Classes(内部类~第一篇英文技术文档翻译)
标签:alc 逻辑 nts blank 场景 ade 错误 getc 内部类
原文地址:https://www.cnblogs.com/lingyejun/p/10085629.html