Java学习笔记八(static、final、代码块等)

无人久伴 提交于 2020-02-28 23:12:40

static关键字的使用:

static:静态的
static可以用来修饰属性、方法、代码块、内部类;
使用static修饰属性:静态变量(类变量)
按是否使用static修饰,属性又可以分为静态属性和非静态属性(实例变量)。
实例变量:如果创建类的多个对象,每个对象都独立的拥有一套类中的非静态属性,通过改变其中一个对象的属性,并不会影响到其他对象的同一属性值。
静态变量:如果创建类的多个对象,多个对象共享一个静态变量;当我们通过其中一个对象改变其中的属性值时,会导致其他对象调用的此静态变量也是修改过的。

几点说明
1、静态变量随着类的加载而加载,可以通过“类。属性”的方式进行调用;
2、静态变量的加载要早于对象的创建;
3、由于类只会加载一次,因此静态变量在内存中也只存在一份:存在于方法去的静态域中;
4、

              类变量                  实例变量
      类       yes                      no	
     对象	   yes		               yes

上面标示类和对象出现时类变量和实例变量的情况。
5、静态变量举例:System.out;Math.PI;

使用static修饰方法:(静态方法)
1、随着类的加载而加载,可以通过“类。静态方法”
2

              静态方法               非静态方法
      类       yes                      no	
     对象	   yes		               yes

3、静态方法中只能调用静态的属性和方法;非静态方法中可以调用静态和非静态的属性和方法。

static的几个注意点
1、static修饰的方法中不能使用this和super关键字。
2、关于静态的属性和方法,我们可以从生命周期的角度去考虑

如何确定一个属性是否需要使用static:
1、属性可以被多个对象共享,不会因为对象的不同而改变;
2、属性中的常量也常常声明为static的;
如何确定一个方法是否需要使用static:
1、操作静态属性的方法,通常声明为static的;
2、一些工具类中的方法也通常声明为static的;比如Arrays、Math、Collections等。

public class StaticTest {
	public static void main(String[] args) {
		
		Chinese.nation = "中国";
		
		
		Chinese c1 = new Chinese();
		c1.name = "姚明";
		c1.age = 40;
		c1.nation = "CHN";
		
		Chinese c2 = new Chinese();
		c2.name = "马龙";
		c2.age = 30;
		c2.nation = "CHINA";
		
		System.out.println(c1.nation);
		
		//编译不通过
//		Chinese.name = "张继科";
		
		
		c1.eat();
		
		Chinese.show();
		//编译不通过
//		Chinese.eat();
//		Chinese.info();
	}
}
//中国人
class Chinese{
	
	String name;
	int age;
	static String nation;
	
	
	public void eat(){
		System.out.println("中国人吃中餐");
		//调用非静态结构
		this.info();
		System.out.println("name :" +name);
		//调用静态结构
		walk();
		System.out.println("nation : " + nation);
	}
	
	public static void show(){
		System.out.println("我是一个中国人!");
		//不能调用非静态的结构
//		eat();
//		name = "Tom";
		//可以调用静态的结构
		System.out.println(Chinese.nation);
		walk();
	}
	
	public void info(){
		System.out.println("name :" + name +",age : " + age);
	}
	
	public static void walk(){
		
	}
}

数组也作为Object类的子类出现,可以调用Object类中声明的方法

public void test1(){
		int[] arr = new int[]{1,2,3};
		print(arr);
		
		System.out.println(arr.getClass().getSuperclass());
		
	}

main()的使用说明:

1、main()方法作为程序的入口;
2、main()方法也是一个普通的静态方法;
3、main()方法可以作为我们与控制台的交互方式;(之前使用的是Scanner)

public class MainTest {
	
	
	public static void main(String[] args) {//入口
		
		Main.main(new String[100]);
		
		MainTest test = new MainTest();
		test.show();
		
	}	
	public void show(){
		
	}
}


class Main{
		
	public static void main(String[] args) {
	
		for(int i = 0;i < args.length;i++){
			args[i] = "args_" + i;
			System.out.println(args[i]);
		}
		
	}
	
}

单例设计模式:

所谓类的单例设计模式,就是采取一定的办法保证在整个软件系统中,某个类只能存在一个对象实例。
单例模式有饿汉式和懒汉式两种形式;
区分饿汉式和懒汉式:
饿汉式:

  • 坏处:对象加载时间过长;
  • 好处:饿汉式是线程安全的;

懒汉式:

  • 好处:对象是延迟创建的;
  • 坏处:目前的写法,线程不安全;(多线程处在进行修改)
public class SingletonTest1 {
	public static void main(String[] args) {
//		Bank bank1 = new Bank();
//		Bank bank2 = new Bank();
		
		Bank bank1 = Bank.getInstance();
		Bank bank2 = Bank.getInstance();
		
		System.out.println(bank1 == bank2);
	}
}

//饿汉式
class Bank{
	
//1.私有化类的构造器
	private Bank(){
		
	}
	
//2.内部创建类的对象
	//4.要求此对象也必须声明为静态的
	private static Bank instance = new Bank();
	
//3.提供公共的静态的方法,返回类的对象
	public static Bank getInstance(){
		return instance;
	}
}
public class SingletonTest2 {
	public static void main(String[] args) {
		
		Order order1 = Order.getInstance();
		Order order2 = Order.getInstance();
		
		System.out.println(order1 == order2);
		
	}
}
class Order{
//1.私有化类的构造器
	private Order() {
		
	}
	//2.声明当前类对象,没有初始化
	//4.此对象也必须声明为static的
	private static Order instance = null;
	//3.声明public、static的返回当前类对象的方法
	public static Order getInstance() {
		if(instance == null) {
			instance = new Order();
		}
		return instance;
	}
}

final关键字的使用:

final:最终的;
final可以用来修饰: 类,方法、变量(包括属性和局部变量);

final修饰类则此类不能被其他的类所继承;比如:String类、System类、StringBuffer类;
final修饰方法:
final修饰方法则此方法不可以被重写;比如:Object中的getClass();
final修饰变量:
final修饰变量:此时的变量称之为常量;

  • final修饰属性:则此属性必须进行赋值,可以考虑的赋值方式有:显示初始化,代码块初始化,构造器初始化;
  • final修饰局部变量:尤其是使用final修饰形参时,表明此形参是一个常量;当我们调用此方法时,给常量形参赋一个实参,一旦赋值之后就只能在方法体内使用此形参,不能够再进行赋值。

static final修饰属性: 全局常量;

public class FinalTest {
	// 一定要进行赋值,且只能赋值一次
	final int WIDTH = 0;
	final int LEFT;
	final int RIGHT;
//  final int DOWN;
	
	{
		LEFT = 1;
	}
	
	public FinalTest(){
		RIGHT = 2;
	}
	
	public FinalTest(int n){
		RIGHT = n;
	}
	
//	public void setDown(int down){
//		this.DOWN = down;
//	}
	
	
	public void doWidth(){
//		width = 20;
	}
	
	
	public void show(){
		final int NUM = 10;//常量
//		NUM += 20;
	}
	
	public void show(final int num){
//		num = 20;//编译不通过
		System.out.println(num);
	}
	
	
	public static void main(String[] args) {
		
		int num = 10;
		
		num = num + 5;
		
		FinalTest test = new FinalTest();
//		test.setDown(3);
		
		test.show(10);
	}
}


final class FinalA{
	
}

//class B extends FinalA{
//	
//}

//class C extends String{
//	
//}

class AA{
	public final void show(){
		
	}
}

class BB extends AA{
	
//	public void show(){
//		
//	}
}

类的成员之代码块:

代码块的作用:用来初始化类、对象;
代码块只能使用statuc进行修饰;分为静态代码块和非静态代码块;
静态代码块
1、静态代码块随着类的加载而执行,且只能执行一次,内部可以有输出语句;
2、作用是初始化类的信息;
3、如果一个类中定义了多个静态代码块,则按照先后顺序执行,静态代码块的执行要早于非静态的代码块;
4、静态代码块只能够调用静态的属性和方法;

非静态代码块
1、非静态代码块睡着对象的创建而执行,且对象创建一次就执行一次,内部可以有输出语句;
2、作用是初始化对象的信息(属性等);
3、如果一个类中定义了多个非静态代码块,则按照先后顺序执行;
4、非静态的代码块可以调用非静态的属性和方法也可以调用静态的属性和方法。

public class BlockTest {
	public static void main(String[] args) {
		
		String desc = Person.desc;
		System.out.println(desc);
		
		Person p1 = new Person();
		Person p2 = new Person();
		System.out.println(p1.age);
		
		Person.info();
	}
}


class Person{
	//属性
	String name;
	
	int age;

	static String desc = "我是一个人";
	
	//构造器
	public Person(){
		
	}
	public Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	//非static的代码块
	{
		System.out.println("hello, block - 2");
	}
	{
		System.out.println("hello, block - 1");
		//调用非静态结构
		age = 1;
		eat();
		//调用静态结构
		desc = "我是一个爱学习的人1";
		info();
	}
	//static的代码块
	static{
		System.out.println("hello,static block-2");
	}
	static{
		System.out.println("hello,static block-1");
		//调用静态结构
		desc = "我是一个爱学习的人";
		info();
		//不可以调用非静态结构
//		eat();
//		name = "Tom";
	}
	
	//方法
	public void eat(){
		System.out.println("吃饭");
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	public static void info(){
		System.out.println("我是一个快乐的人!");
	}
	
}

对属性进行赋值的先后顺序:
①默认初始化
②显示初始化/③代码块中初始化
④构造器中初始化
⑤有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值
其中②和③不分先后;

关于静态代码块、非静态代码块以及构造器在子父类中的执行顺序:
总结就是:由父及子,静态先行;(非静态代码块要在对象创建时对对象进行初始化,因此在构造器之前。)
注意:如果main函数中有输出语句,也要在静态之后,因为要先加载完类的信息后才开始执行程序。

class Root{
	static{
		System.out.println("Root的静态初始化块");
	}
	{
		System.out.println("Root的普通初始化块");
	}
	public Root(){
		super();
		System.out.println("Root的无参数的构造器");
	}
}
class Mid extends Root{
	static{
		System.out.println("Mid的静态初始化块");
	}
	{
		System.out.println("Mid的普通初始化块");
	}
	public Mid(){
		super();
		System.out.println("Mid的无参数的构造器");
	}
	public Mid(String msg){
		//通过this调用同一类中重载的构造器
		this();
		System.out.println("Mid的带参数构造器,其参数值:"
			+ msg);
	}
}
class Leaf extends Mid{
	static{
		System.out.println("Leaf的静态初始化块");
	}
	{
		System.out.println("Leaf的普通初始化块");
	}	
	public Leaf(){
		//通过super调用父类中有一个字符串参数的构造器
		super("尚硅谷");
		System.out.println("Leaf的构造器");
	}
}
public class LeafTest{
	public static void main(String[] args){
		new Leaf(); 
		System.out.println();
		new Leaf();
	}
}

执行结果:
Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:尚硅谷
Leaf的普通初始化块
Leaf的构造器

Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:尚硅谷
Leaf的普通初始化块

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!