JAVA基础学习笔记(8):static关键字、单例模式、main方法、代码块、final关键字

  • Post author:
  • Post category:java

1 static关键字

static是静态的意思,可以用来修饰属性、方法、代码块、内部类

1.1 static修饰变量

1.1.1 静态变量与实例变量

实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。

1.1.2 静态变量的说明

1.静态变量随着类的加载而加载。可以通过”类.静态变量”的方式进行调用
2.静态变量的加载要早于对象的创建
3.由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中

1.1.3 静态变量的使用

public class StaticTest {
	public static void main(String[] args) {
		
		Chinese c1 = new Chinese();
		c1.name = "孔子";
		c1.age = 100;
		c1.location = "ZY";
		
		Chinese c2 = new Chinese();
		System.out.println(c2.location);// ZY
		
		//可以通过直接调用类名的方法来
		Chinese.location = "zhongyuan";
		System.out.println(c1.location);// zhongyuan
	}
}

class Chinese{
	String name;
	int age;
	static String location;
}

1.1.4 静态变量与实例变量的内存解析

在这里插入图片描述

1.1.5 静态变量的应用场景

1.属性是可以被多个对象所共享的,不会随着对象的不同而不同的。
2.类中的常量也常常声明为static

1.2 static修饰方法

1.2.1 静态方法与非静态方法

1.随着类的加载而加载,可以通过”类.静态方法”的方式进行调用
2.静态方法中,只能调用静态的方法或属性;非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性

1.2.2 静态方法的说明

1.在静态的方法内,不能使用this关键字、super关键字
2.关于静态属性和静态方法的使用,大家都从生命周期的角度去理解

1.2.3 静态方法的使用

public class StaticTest {
	public static void main(String[] args) {
		
		Chinese c1 = new Chinese();
		c1.name = "孔子";
		c1.age = 100;
		c1.location = "ZY";
		
		Chinese c2 = new Chinese();
		System.out.println(c2.location);// ZY
		
		Chinese.location = "zhongyuan";
		System.out.println(c1.location);// zhongyuan
		
		c2.show();
		Chinese.show();
	}
}

class Chinese{
	String name;
	int age;
	static String location;
	
	public static void show() {
		//无法调用非静态方法或属性
		//System.out.println(age);
		//info1();
		//可以调用静态变量和静态方法,因为生命周期相同
		info2();
		System.out.println(location);
	}
	
	public void info1() {
		System.out.println("info1");
	}
	
	public static void info2() {
		System.out.println("info2");
	}
}

1.2.4 静态方法的应用场景

1.操作静态属性的方法,通常设置为static的
2.工具类中的方法,习惯上声明为static的。 比如:Math、Arrays、Collections

2 单例模式

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。 如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象, 静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的

2.1 饿汉式

public class SingletonTest1 {
	public static void main(String[] args) {
		Bank bank1 = Bank.getInstance();
		Bank bank2 = Bank.getInstance();
		System.out.println(bank1 == bank2); //true
	}
}

//饿汉式
class Bank{
	
	//1.私有化构造器
	private Bank() {
		
	}
	
	//2.内部创建类的对象
	//4.要求此对象的生命也必须是静态的
	private static Bank instance = new Bank();
	
	//3.提供公共的静态的方法,返回类的对象
	public static Bank getInstance() {
		return instance;
	}
}

2.2 懒汉式

public class SingletonTest2 {
	public static void main(String[] args) {
		Order o1 = Order.getInstance();
		Order o2 = Order.getInstance();
		System.out.println(o1 == o2);//true
	}
}

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;
	}
}

3 main方法

3.1 main方法的说明

由于Java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是 public,又因为Java虚拟机在执行main()方法时不必创建对象,所以该方法必须 是static的,该方法接收一个String类型的数组参数,该数组中保存执行Java命令时传递给所运行的类的参数。
又因为main() 方法是静态的,我们不能直接访问该类中的非静态成员,必须创
建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员,这种情况,我们在之前的例子中多次碰到。
总结:
1.main()方法作为程序的入口
2.main()方法也是一个普通的静态方法
3.main()方法可以作为我们与控制台交互的方式

3.2 eclipse传参使用main方法

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

在这里插入图片描述
在这里插入图片描述

3.3 命令行使用main方法

将MainTest.java文件放入D:\code中,将其中的导包代码去掉。
在这里插入图片描述

4 代码块

4.1 代码块的作用

用来初始化类、对象。只能用static关键字来修饰。

4.2 静态代码块和非静态代码块

  • 静态代码块:
    1.内部可以有输出语句
    2.随着类的加载而执行,而且只执行一次
    3.作用:初始化类的信息
    4.如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
    5.静态代码块的执行要优先于非静态代码块的执行
    6.静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
  • 非静态代码块:
    1.内部可以有输出语句
    2.随着对象的创建而执行,每创建一个对象执行一次非静态代码块
    3.作用:可以在创建对象时,对对象的属性等进行初始化
    4.如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
    5.非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法

4.3 代码块的使用

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

class Person{
	//属性
	String name;
	int age;
	static String desc = "我在学习java";
	
	//构造器
	public Person(){
		
	}
	public Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	//非静态代码块
	{
		System.out.println("hello, block");
	}
	//静态代码块
	static {
		System.out.println("hello, static block!");
		desc = "学习java的同时学习很多其他语言!!";
	}
	
	//方法
	public void eat() {
		System.out.println("吃饭");
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}
	public static void info() {
		System.out.println("Perosn类中的info方法!!");
	}
} 

4.4 属性赋值的先后顺序

可进行初始化赋值的位置:
①默认初始化
②显式初始化/⑤在代码块中赋值
③构造器中初始化
④有了对象以后,可以通过”对象.属性”或”对象.方法”的方式,进行赋值
执行的先后顺序:① – ② / ⑤ – ③ – ④

5 final关键字

final可以用来修饰的结构:类、方法、变量

5.1 final修饰类、方法、变量

1.final标记的类不能被继承,如:String类、System类、StringBuffer类
2.final标记的方法不能被子类重写,如:Object类中的getClass()
3.final标记的变量(成员变量或局部变量)即称为常量,可以考虑赋值的位置:显式初始化、代码块中初始化、构造器中初始化

5.2 final修饰局部变量

使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

5.3 全局常量

使用static final修饰的属性即全局常量

本节练习

ex1

例:一个圆类的测试程序,使用静态变量init来生成每个圆的编号,使用静态变量total来生成圆的总个数。使用静态方法getTotal来查看圆的总个数。

public class CircleTest {
	public static void main(String[] args) {
		
		Circle c1 = new Circle();
		Circle c2 = new Circle();
		Circle c3 = new Circle(1.0);
		
		System.out.println("c1的id:" + c1.getId());
		System.out.println("c2的id:" + c2.getId());
		System.out.println("c3的id:" + c3.getId());
		System.out.println("圆的总数为: " + c1.getTotal() );
	}

}

class Circle{
	
	private double radius;
	private int id;
	
	private static int total;
	private static int init = 1001;
	
	public Circle(){
		id = init++;
		total++;
	}
	
	public Circle(double radius){
		this();
		this.radius = radius;
		
	}

	public double getRadius() {
		return radius;
	}

	public void setRadius(double radius) {
		this.radius = radius;
	}

	public int getId() {
		return id;
	}
	
	public double  findArea() {
		return Math.PI * radius * radius;
	}

	public static int getTotal() {
		return total;
	}	
}

参考资料:
[1]尚硅谷宋康红java基础教程


版权声明:本文为LeavingBook原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。