嵌套类(nested classes)
在Java应用程序语言中允许在一个类中定义另外一个类,这样的类叫做嵌套类:
class OuterClass {//外部类,顶级类
...
class NestedClass {//嵌套类
...
}
}
嵌套类的分类
特别的,嵌套类可以分为静态和非静态的。声明为静态的叫做静态嵌套类(static nested classes),而非静态的可以分为inner class ,local classes anonymous class
public class OuterClass {//顶级类,外部类
interface HelloWorld {
void greet();
void greetSomeone(String someone);
}
/**
* 静态嵌套类
*/
static class StaticNestedClass {
}
/**
* 内部类
* */
class InnerClass {
}
public void sayHello() {
/***
*局部类
*/
class LocalClass implements HelloWorld {
String name = "world";
public void greet() {
greetSomeone("world");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hello " + name);
}
}
HelloWorld englishGreeting = new LocalClass();
/**
* 匿名类
* */
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
englishGreeting.greet();
frenchGreeting.greetSomeone("Fred");
}
public static void main(String... args) {
OuterClass myApp =
new OuterClass();
myApp.sayHello();
}
}
为什么使用嵌套类
- 对于那种仅在一个地方使用的类,嵌套的方式是一种很好的逻辑分组方式。假如一个类只对其他类中的一个类有用,这是非常符合逻辑的将这个类嵌套在那个使用它的类里面,使他们连在一起。嵌套就好像是一个“帮助类”一样,使他们的封装更加的简化
- 增加封闭性。考虑一下这样的情景,两个顶级类A和B,在类B中要用权限能够使用到A的组成成分(域/方法),那么对于A的组成成分要么暴露(public)出来(get/set也是),要么不给B这个权限(private)。(个人理解:类A中组成成分只想给类B使用)。那么,可以通过将类B嵌套在类A中,A的组成成分就可以声明为private,类B又能有权限使用到,还有,对于类B,它也可以对除了类A之外的其他类隐藏(也就是声明为private)
- 增加代码的可读性和可维护性。在顶级类中嵌套的类 ,嵌套类的代码更加接近它被使用的地方。(离得近)
静态嵌套类(static nested classes)
package com.company;
import java.util.Random;
/**
*① 可以使用访问修饰符
*②对外部类方法和域的权限:对声明为static的域和方法有使用权限,即使它们申明为private
*③是否可以在类中创建static的域和method 可以,也可以声明接口
*/
public class StaticNestedClassTest {
static int i = 0;
int a = 0;
final static Object o = new Random();
private static void method1() {
}
public static void method2() {
}
public void method3() {
}
/**
* static nested classes 可以使用访问修饰符修饰,可以访问到外部类的static 域和方法,在static nested classes内部可以创建任何东西
* 就像是另外的一个顶级类一样使用,不过static nested classes却可以访问它外部类的一些private的静态域和方法,而其他的顶级类却不能
* */
static class StaticNestedClass {
static int s = 0;
Object object = new Object();
private static void method4() {
System.out.println(i);//可以引用外部类中的静态域
// System.out.println(a);//非静态类型的a不能在一个静态环境中引用
System.out.println(o.toString());//引用外部类静态常量
method1();//外部类的静态方法,即使它申明为private
method2();
// method3();//非静态方法不能在一个静态环境中引用
}
public void method5() {
System.out.println(i);
// System.out.println(a);//非静态类型的a不能在一个静态环境中引用
method1();
method2();
// method3();//非静态方法不能在一个静态环境中引用
}
interface Test{
}
class Test1 {
}
}
/**
* 除了StaticNestedClassTest类之外的类,其他类无法访问到这个私有的StaticNestedClass1
* */
private static class StaticNestedClass1{
}
public static void main(String[] args) {
//创建一个静态嵌套类实例
StaticNestedClassTest.StaticNestedClass staticNestedClass = new StaticNestedClassTest.StaticNestedClass();
}
}
non-static nested classes
inner classes
package com.company;
import java.util.Random;
/**
*①可以使用访问修饰符
*②对外部类方法和域的权限:所有的方法和域都有使用权,即使声明为private
*③是否可以在类中创建static的域和method 不可以,(可以声明全局常量,基本数据类和String 的final static String s = "sad"; final static int g = 0;) 也不可以声明接口
* 相关:A constant variable is a variable of primitive type or type String that is declared final and initialized with a compile-time constant expression.
* A compile-time constant expression is typically a string or an arithmetic expression that can be evaluated at compile time.
* 涉及到编译时。不解释 ,知道就ok
*/
public class InnerClassTest {
static int i = 0;
private int a = 0;
final static Object o = new Random();
private static void method1() {
}
public static void method2() {
}
public void method3() {
}
/**
* InnerClass 可以使用访问修饰符修饰
*/
public class InnerClass {
private void method4() {
/**
* 可以使用外部类的所用域和方法,即使是private,
* */
System.out.println(i);
System.out.println(a);
System.out.println(o.toString());
method1();
method2();
method3();
}
//不可以在inner class中有静态的声明
// private static void method5(){
//
// }
// static int a;
// interface test{
//
// }//interface 在本质上市static属性的,所以也是不可以
/**
* 对于像基本类型,String 这两种情况,因为本身它们是属于常量
* 被final static 修饰的变量可以认为是全局的常量,
* 很明显,s g ob 都是一个常量,但是s g 指向的实例对象依旧还是常量,而ob指向的确不是
*
*/
final static String s = "sad";
final static int g = 0;
//不可以在inner class中有静态的声明
// final static Object ob = new Random();
/**
* 为什么在innerclass中不可以有static的方法和变量和一些常量,因为在inner class中是包含有一个
* 外部类对象实例的,要不是就不能够直接的访问到外部类的域和方法了,而static nested class里面没有包含
* 它外部类的实例对象所以他只能使用到static的域和方法
* */
}
class InnerClass1 {
}
}
创建实例:
package com.company;
public class Main{
public static void main(String[] args) throws ClassNotFoundException {
//报错,提示InnerClass不是一个外部顶级类
// InnerClassTest.InnerClass innerClass = new InnerClassTest.InnerClass();
InnerClassTest innerClassTest = new InnerClassTest();
InnerClassTest.InnerClass innerClass = innerClassTest.new InnerClass();
//从这里可以印证:InnerClass 内部是有一个InnerClassTest的实例对象的,
//InnerClass 的对象实例 依存它外部类InnerClassTest实例,先有我外部类实例,再有InnerClass实例
}
}
local classes
localclass 可以说是inner class 的继续限制版,inner class里面 不能定义static域和方法和一些常量,localclass也是不能的
看列子:
package com.company;
import java.util.Random;
/**
*①不能使用访问修饰符
*②对外部类方法和域的权限:对于在非静态块的localClass 对外部类的所有域和方法都有使用权,(即使声明为private)
* 在静态块定义的localClass只对外部类声明为是static的域和方法有使用权(即使声明为private)
*③是否可以在类中创建static的域和method 不可以,(可以声明全局常量,基本数据类和String 的final static String s = "sad";
* final static int g = 0;) 也不可以声明接口
* ***即使localClass在static块出定义也不可以
*④对于方法(块)中的局部变量/参数 只有当它们是final/effective final的时候才可以在LocalClass中使用,详细看代码
*/
public class LocalClassTest {
static int i = 0;
private int a = 0;
final static Object o = new Random();
private static void method1() {
}
public static void method2() {
}
public void method3() {
}
/**
* 既然叫局部,当然是不能使用访问修饰符啦
* */
//定义在static 块 中
static {
class LocalClass1 {
private void method8(){
System.out.println(i);
// System.out.println(a);//静态中不能引用非静态的变量
System.out.println(o.toString());
}
}
}
//定义在构造方法中
public LocalClassTest() {
class LocalClass2 {
}
for (int i = 0; i < 5; i++) {//定义在for循环块 中
class LocalClass3 {
}
}
}
//定义在普通的方法中
private void method4(int jj,Object ll) {
final int aa = 0;
int bb = 5;
// bb++;
// ll = null;
//ll 和bb 是effectively final才能被LocalClass使用 。effectively final是在JDK8才出现的,所以8之前的只有final的才能在LocalClass中使用
class LoadClass4 {
public void method6() {
/**
* 可以使用外部类的所用域和方法,即使是private,
* */
System.out.println(i);
System.out.println(a);
System.out.println(o.toString());
method1();
method2();
method3();
/**
* 对于包含LocalClass的块的一些局部变量,这些变量要么是final要么是effectively final(这个变量这能赋值一次)
* */
System.out.println(jj);
System.out.println(ll);
System.out.println(aa);
System.out.println(bb);
// jj++;
// ll = null;
// bb = 80;
}
//不可以在inner class中有静态的声明
// private static void method5(){
//
// }
// static int a;
// interface test{
//
// }//interface 在本质上市static属性的,所以也是不可以
final static String s = "sad";
final static int g = 0;
//不可以在inner class中有静态的声明
// final static Object ob = new Random();
}
}
//定义在static方法中
/**
* 这个特殊
*/
private static void method5(int jj,Object ll) {
final int aa = 0;
int bb = 5;
class LocalClass5 {
private void method7() {
System.out.println(i);
// System.out.println(a);//静态中不能引用非静态的变量
System.out.println(o.toString());
method1();
method2();
// method3();//静态中不能引用非静态的变量
/**
*
* */
System.out.println(jj);
System.out.println(ll);
System.out.println(aa);
System.out.println(bb);
// jj++;
// ll = null;
// bb = 80;
}
// 不可以在inner class中有静态的声明
// private static void method5() {
// }
// static int a;
// interface test{
//
// }//interface 在本质上市static属性的,所以也是不可以
final static String s = "sad";
final static int g = 0;
//不可以在inner class中有静态的声明
// final static Object ob = new Random();
}
if (true) {//定义在if块中
class LocalClass6 {
}
}
}
}
anonymous classes
package com.company;
import java.util.Random;
/**
* Anonymous classes enable you to make your code more concise.
* They enable you to declare and instantiate a class at the same time.
* 同时声明和实例化
* They are like local classes except that they do not have a name.
* Use them if you need to use a local class only once.
* 其实本质上说,anonymousclass是表达式,如
* new HelloWorld() {
* String name = "tout le monde";
* <p>
* public void greet() {
* greetSomeone("tout le monde");
* }
* <p>
* public void greetSomeone(String someone) {
* name = someone;
* System.out.println("Salut " + name);
* }
* };
*表达式包含:①new关键字 ② 要实现的接口或者继承的抽象类③在()中包含构造函数的参数,假如又需要的话
* 用的最多的就是GUI 事件当中
*
*
*/
public class AnonymousClassTest {
static int i = 0;
private int a = 0;
final static Object o = new Random();
private static void method1() {
}
public static void method2() {
}
public void method3() {
}
interface HelloWorld {
public void greet();
public void greetSomeone(String someone);
}
abstract class HelloWorldTest {
abstract void greet();
abstract void greetSomeone(String someone);
}
public void sayHello(int jj, Object ll) {
final int aa = 0;
int bb = 5;
// bb++;
// ll = null;
//ll 和bb 是effectively final才能被LocalClass使用 。effectively final是在JDK8才出现的,所以8之前的只有final的才能在LocalClass中使用
class EnglishGreeting implements HelloWorld {
String name = "world";
public void greet() {
greetSomeone("world");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hello " + name);
}
}
//使用LocalClass实例化englishGreeting
HelloWorld englishGreeting = new EnglishGreeting();
//使用anonymousClass实例化
HelloWorld frenchGreeting = new HelloWorld() {
String name = "tout le monde";
public void greet() {
greetSomeone("tout le monde");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Salut " + name);
}
};
HelloWorld spanishGreeting = new HelloWorld() {
String name = "mundo";
public void greet() {
greetSomeone("mundo");
}
public void greetSomeone(String someone) {
name = someone;
System.out.println("Hola, " + name);
}
};
englishGreeting.greet();
frenchGreeting.greetSomeone("Fred");
spanishGreeting.greet();
//使用anonymousClass
HelloWorldTest helloWorldTest = new HelloWorldTest() {
private void method4() {
/**
* 可以使用外部类的所用域和方法,即使是private,
* */
System.out.println(i);
System.out.println(a);
System.out.println(o.toString());
method1();
method2();
method3();
/**
* 对于包含LocalClass的块的一些局部变量,这些变量要么是final要么是effectively final(这个变量这能赋值一次)
* */
System.out.println(jj);
System.out.println(ll);
System.out.println(aa);
System.out.println(bb);
// jj++;
// ll = null;
// bb = 80;
}
@Override
void greet() {
}
@Override
void greetSomeone(String someone) {
}
//不可以在inner class中有静态的声明
// private static void method5(){
//
// }
// static int a;
// interface test{
//
// }//interface 在本质上市static属性的,所以也是不可以
final static String s = "sad";
final static int g = 0;
//不可以在inner class中有静态的声明
// final static Object ob = new Random();
};
}
//使用anonymousClass
HelloWorldTest helloWorldTest = new HelloWorldTest() {
@Override
void greet() {
}
@Override
void greetSomeone(String someone) {
}
};
}