Java面向对象--代码块(初始化块)和内部类

本篇博客介绍Java学习过程中类的成员之代码块(初始化块)和内部类的具体使用。


目录:

☍ 代码块(初始化块)

☍ 内部类(Inner class)


☍ 代码块(初始化块)

代码块的概述

☃ 代码块(或初始化块)的作用:对Java类或对象进行初始化操作

☃ 代码块(或初始化块)的分类:一个类中代码块只能被static修饰符修饰,若由static修饰称为静态代码块(static block),没有使用static修饰的,为非静态代码块

☃ static 代码块化 通常用于初始化static

class Person{
	public static String nation;
	static{
		nation = "China";
	}
}

静态代码块:用static修饰的代码块

➊ 可以有输出语句

➋ 可以对类的属性、类的声明进行初始化操作

➌ 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。

➍ 若有多个静态的代码块,那么按照从上到下的顺序依次执行。

➎ 静态代码块的执行要先于非静态代码块。

➏ 静态代码块随着类的加载而执行,且只执行一次。

静态代码块:用static修饰的代码块

➊ 可以有输出语句。

➋ 可以对类的属性、类的声明进行初始化操作。

➌ 除了调用非静态的结构外,还可以调用静态的变量或方法。

➍ 若有多个非静态的代码块,那么按照从上到下的顺序依次执行。

➎ 随着对象的创建而执行,创建一次执行一次。且先于构造器执行。

public class BlockTest {
	public static void main(String[] args) {
		String desc = Person.desc;
		System.out.println("index:" + Person.index);
		System.out.println("index:" + Person.index);
		Person person = new Person();
		System.out.println("index:" + Person.index);
        Person person = new Person();
		System.out.println("index:" + Person.index);
		System.out.println(person.toString());
	}
}

class Person{
	//属性
	static String name;
	int age;
	static int index = 10;
	static String desc = "人类";
	//构造器
	public Person() { }
	//非静态代码块
	{
		age = 19;   //可以使用静态属性和非静态属性
		name = "张三";
		index++;
		System.out.println("not static block");
        getInfo();  //可以调非静态方法和静态方法
        eat();
	}
	//静态代码块
	static {
        //	age = 20;  不能使用非静态变量
		name = "李四";
		index++;
		System.out.println("static block");
        getInfo();
        //	eat();   不能使用非静态方法
	}
	//方法
	public void eat() {
		System.out.println("吃饭");
	}
	public static void getInfo() {
		System.out.println("我是一个快乐的人");
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
}
/*输出和说明
static block   //静态代码块随着类的加载而执行,只执行一次
我是一个快乐的人
index11	
index11
not static block	//随着对象的创建而执行
我是一个快乐的人
吃饭
index12
not static block	 //创建一个对象执行一次
我是一个快乐的人
吃饭
index13
Person [name=张三, age=19]   //非静态的代码块晚于静态代码执行
*/

程序中成员变量赋值的执行顺序


☍ 内部类(Inner class)

内部类概述

☃ 内部类是Java的五大成员之一,当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。

☃ 在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。

☃ Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。

☃ Inner class的名字不能与包含它的外部类类名相同。

☃ 内部类可分为成员内部类(static成员内部类和非static成员内部类)以及局部内部类(不谈修饰符)、匿名内部类

成员内部类

class 外部类{
	//成员变量声明
    //成员方法声明
    //构造器声明
    class 成员内部类{
    }
}

☃ 可以将成员内部类看成外部类的成员(类似一个成员方法)或者是外部类中的一个类,同时具有成员和类的部分特性。

☃ 和外部类(只能声明为public 或者省略默认)不同,Inner class还可以声明为private或protected;

☃ 可以调用外部类的结构

☃ Inner class 可以声明为static的,但此时就不能再使用外层类的非static的成员变量;

☃ 可以在内部定义属性、方法、构造器等结构

☃ 可以声明为abstract类 ,因此可以被其它的内部类继承

☃ 可以声明为final的

☃ 编译以后生成OuterClass$InnerClass.class字节码文件(也适用于局部内部类)

注意:

➥ 非static的成员内部类中的成员不能声明为static的,只有在外部类或static的成员内部类中才可声明static成员

➥ 外部类访问成员内部类的成员,需要“内部类.成员”或“内部类对象.成员”的方式

➥ 成员内部类可以直接使用外部类的所有成员,包括私有的数据

➥ 当想要在外部类的静态成员部分使用内部类时,可以考虑内部类声明为静态的

局部内部类

//声明局部内部类
class 外部类{
    //声明在方法体中
	方法(){
		class 局部内部类1{
		}
	}
    //声明在代码块内
	{
		class 局部内部类2{
		}
	}
    //声明在构造器中
    public 外部类名(){
    	class 局部内部类3{
		}
    }
}

☃ 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方
都不能使用该类

☃ 但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型

public class InnerClassTest{
    //开发中很少使用
    public void method(){
        //局部内部类
        class AA{
            //....
        }
    }
    //常见使用方式
    //返回了一个实现了Comparable节后的类的对象
    public Comparable getComparable(){
        //创建一个实现了Comparable接口的类:局部内部类
        class MyComparable implements Comparable{
            @Override
            public int compareTo(Object o){
                //....
                return 0;
            }
        }
        return new MyComparable();
    }
}

局部内部类特点:

☄ 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和\(符号,如:Person\)PetDog.class ,局部内部类还会加上数字编号,如:Person$1AA.class。

☄ 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类。

☄ 局部内部类可以使用外部类的成员,包括私有的。

☄ 局部内部类可以使用外部方法的局部变量,但是必须是final的,jdk7之前必须声明final关键字,jdk之8之后可以省略final关键字,但是一旦在局部类中使用了该变量,系统就会默认该变量为final的。由局部内部类和局部变量的声明周期不同所致。常用于Android开发。

static void method1(){
	int num1= 1;
	//num1++; 报错    
	 class BB{
		int a = 1;
		public int add() {			
//jdk7之前必须将num1定义为final的,否则编译不通过,jdk8之后会默认为final
			num1 = 10;
			a += num1;
			return a;
		}
	}
	 //num1 ++;  报错
     //二选一,如果在内部类之后使用,内部类就不能使用,
	 //内部类中一旦使用就会默认该变量为final的,之后就不可以修改了
}

☄ 局部内部类和局部变量地位类似,不能使用public,protected,default,private

☄ 局部内部类不能使用static修饰,因此也不能包含静态成员

内部类的使用

创建成员内部了的实例化对象:

//创建静态成员内部类实例
外部类.内部类 变量名 = new 外部类.内部类构造器(参数列表);
OutClass.InnerClass o1 = new OutClass.InnerClass();
//创建非静态成员内部类实例
外部类 外部类对象变量名 = new 外部类构造器(参数列表);
OutClass out = new OutClass();
外部类.内部类 变量名 =  外部类对象变量名.new 内部类构造器(参数列表);
OutClass.InnerClass o2 = out.new InnerClass();

内部类调用成员:

☄ 如果内部类与外部类成员不重名直接调用,但是要注意static关键字的限制

☄ 如果内部类与外部类成员重名了,则直接使用变量名/方法名调用的是内部类方法中的局部变量,若没有局部变量效果相当于this.变量名/this.方法名,调用的是内部类的成员

☄ 如果调用外部类的成员,对于外部类的静态成员使用外部类.成员名方式调用,对于非静态外部类成员,使用外部类.this.成员名的方式调用

匿名内部类

☃ 匿名内部类不能定义任何静态成员、方法和类,只能创建匿名内部类的一个实例。一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。

☃ 格式:

new 父类构造器(实参列表)or 实现接口(){
	// 匿名内部类的类体部分
} 

匿名内部类特点:

☄ 匿名内部类必须继承父类或实现接口

☄ 匿名内部类只能有一个对象

☄ 匿名内部类对象只能使用多态形式引用

public class InnerClassTest{
    ////匿名内部类(实现了Comparable接口),并将对象方法
    public Comparable getComparable(){
        //创建一个实现了Comparable接口的类:局部内部类
               return new Comparable() {
        	 @Override
             public int compareTo(Object o){
                 //....
                 return 0;
             }
		};
    }
}

本博客与CSDN博客༺ཌ༈君☠纤༈ད༻同步发布

posted @ 2020-03-20 19:22  ༺ཌ༈君☠纤༈ད༻  阅读(430)  评论(0编辑  收藏  举报