Java_08【内部类和代码块】

代码块

进入代码块之前先看一个经典题型

public class HelloA {
//构造方法
public HelloA(){
System.out.println("Hello A!父类构造方法");
}
//非静态代码块
{
System.out.println("i'm A class.父类非静态代码块");
}
//静态代码块
static{
System.out.println("static A 父类静态代码块");
}
}
public class HelloB extends HelloA {
//构造方法
public HelloB(){
System.out.println("Hello B! 构造方法");
}
//非静态代码块
{
System.out.println("i'm B class.非静态代码块");
}
//静态代码块
static{
System.out.println("static B 静态代码块");
}
public static void main(String[] args) {
System.out.println("---start---");
new HelloB();
new HelloB();
System.out.println("---end---");
}
}
/**
static A 父类静态代码块
static B 静态代码块
---start---
i'm A class.父类非静态代码块
Hello A!父类构造方法
i'm B class.非静态代码块
Hello B! 构造方法
i'm A class.父类非静态代码块
Hello A!父类构造方法
i'm B class.非静态代码块
Hello B! 构造方法
**/

观察上述代码直接进入主题 按照执行顺序介绍

01静态代码块

static{
        System.out.println("静态代码块");
    }

执行时间:在这个类被加载时就执行,优先于各种代码块其中内容最早执行。如果有多个代码块则按照静态代码块顺序执行
作用:有些代码需要在项目启动的时候就执行,这时候就需要静态代码块。比如一个项目启动需要加载的很多配置文件等资源,我们就可以都放入静态代码块中。
特点
1.特点是在一个类的内部由static关键字修饰用{}大括号包括的代码块
2.有些代码需要在项目启动的时候就执行,这时候就需要静态代码块。比如一个项目启动需要加载的很多配置文件等资源,我们就可以都放入静态代码块中。
3.静态代码块不能存在任何方法体中
对于普通方法,由于普通方法是通过加载类,然后new出实例化对象,通过对象才能运行这个方法,而静态代码块只需要加载类之后就能运行了。
对于静态方法,在类加载的时候,静态方法也已经加载了,但是我们必须要通过类名或者对象名才能访问,也就是说相比于静态代码块,静态代码块是主动运行的,而静态方法是被动运行的。
4.静态代码块不能访问普通变量,普通变量只能通过对象来调用,是不能放在静态代码块中的。

02构造方法

{
        System.out.println("构造代码块");
    }

不能被构造函数的概念混淆,构造代码块只用{}声明的代码块
执行时间: 构造代码块在创建对象时被调用,每次创建对象都会调用一次,但是优先于构造函数执行。而且
不实例化对象,构造代码块是不会执行的。
如果存在多个构造代码块,则执行顺序按照书写顺序依次执行。
作用:构造函数的作用类似,都能对对象进行初始化,并且只要创建一个对象,构造代码块都会执行一次。

03构造函数

public HelloA(){
System.out.println("Hello A!父类构造方法");
}

1.构造函数的命名必须和类名完全相同。在java中普通函数可以和构造函数同名,但是必须带有返回值;
2.构造函数的功能主要用于在类的对象创建时定义初始化的状态。没有返回值保证了它不仅什么也不用自动返回,而且根本不能有任何选择。而其他方法都有返回值,即使是void返回值。
尽管方法体本身不会自动返回什么,但仍然可以让它返回一些东西,而这些东西可能是不安全的;
3.构造函数不能被直接调用,必须通过new运算符在创建对象时才会自动调用;
一般的方法是在程序执行到它的时候被调用的;
4.当定义一个类的时候,通常情况下都会显示该类的构造函数,并在函数中指定初始化的工作也可省略,不过Java编译器会提供一个默认的构造函数.此默认构造函数是不带参数的。

04普通代码块

public void test(){
	{
		System.out.println("普通代码块");
	}
}

普通代码块和构造代码块的区别是,构造代码块是在类中定义的,而普通代码块是在方法体中定义的。且普通代码块的执行顺序和书写顺序一致。

05执行顺序

一个类中
静态代码块>构造代码块>构造函数>普通代码块 
继承关系中
1.首先执行父类静态的内容,父类静态的内容执行完毕后,接着去执行子类的静态的内容,
2.再去看父类有没有构造代码块,如果有就执行父类的构造代码块,父类的构造代码块执行完毕,接着执行父类的构造方法;
3.父类的构造方法执行完毕之后,它接着去看子类有没有构造代码块,如果有就执行子类的构造代码块。
4.子类的构造代码块执行完毕再去执行子类的构造方法。

总结:静态代码块内容先执行,接着执行父类构造代码块和构造方法,然后执行子类构造代码块和构造方法。

内部类

01成员内部类

成员内部类是最普通的内部类,它的定义为位于另一个类的内部。

class Outer{   	//外部类
	int i=1;
	private double dd = 0;
	public static int count = 1;
	public Outer(int i){
		this.i=i;
	}
	
	public void test(){
			System.out.println("wudiOuter");
		}
		
	class Inner{	//内部类
		int i=2;
		public void getInner(){
			System.out.println("Inner");
			System.out.println(dd);
			System.out.println(count);
		}
		public void test(){
			System.out.println("wudi");
		}
	}
}

成员内部类访问外部类
成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
当成员内部类拥有和外部类同名的成员变量或者方法时,会有隐藏现象。会默认访问成员内部类的成员方法或者变量。如果要访问外部类同名的方法或者变量

外部类.this.成员方法
Outer.this.test();
//wudiOuter
外部类.this.成员变量
System.out.println(Outer.this.i);
// 1

外部类访问内部类
外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问

	new Outer().test();
	// System.out.println("wudi");

成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。

        Outter outter = new Outter();
        Outter.Inner inner = outter.new Inner();  //必须通过Outter对象来创建

权限
内部类权限private 这只能通过外部类访问内部类
public修饰则任何都能访问
protected修饰,则只能在同一个包下或者继承外部类的情况下访问;
默认访问权限,则只能在同一个包下访问。
外部类只能被public和默认问两种权限修饰。

02局部内部类

局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。

class Outer{
public Outer(){		//外部类
}
	class Inner{	//内部类
		public Inner(){
		}
		public void test(){	
			class localInner{		//局部内部类
				System.out.println("局部内部类");
			}
		}
	}
}

局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。

03匿名内部类

匿名内部类应该是平时我们编写代码时用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。

interface MyInterface {
	void test();
}
class Outter {
	private int num;
 public void display(int para) {
	// 匿名内部类,实现了MyInterface接口
		new MyInterface(){
	@Override
  public void test() {
		System.out.println("匿名内部类"+para);
			}
		}.test();
	}
}
  1. 匿名内部类是没有访问修饰符的。
  2. 匿名内部类必须继承一个抽象类或者实现一个接口
  3. 匿名内部类中不能存在任何静态成员或方法
  4. 匿名内部类是没有构造方法的,因为它没有类名。
  5. 与局部内部相同匿名内部类也可以引用方法形参。此形参也必须声明为 final

04静态内部类

静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似。
不能使用外部类的非static成员变量或者方法。
因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。

class Outer{

private static String msg = "Hello World" ;
// ********************************

static class Inner{ //定义一个内部类
	public void print(){ //此时只能使用外部类中的static操作
		System.out.println(msg); //调用msg属性
		}
	}
// ********************************
//在外部类中定义一个方法,该方法负责产生内部类对象并且调用print()方法
public void fun(){
		Inner in = new Inner(); //内部类对象
		in.print(); // 内部类提供的print()方法
		}
	}
  1. 静态内部类的创建是不需要依赖于外围类,可以直接创建
  2. 静态内部类不可以使用任何外围类的非static成员变量和方法,而内部类则都可以

猜你喜欢

转载自blog.csdn.net/qq_36390039/article/details/88776969