类变量为所有对象共享,类变量的生命周期同类一样,而每个对象都有独属于自己的示例变量,实例变量的生命周期同对应实例一样,公家的和自家的区别
public class Student {
static int grade; //年级
String name; //姓名
}
public class StaticDemo1 {
public static void main(String[] args) {
Student s1 = new Student(); //定义学生对象1
Student s2 = new Student(); //定义学生对象2
Student.grade = 1; //通过类名访问类变量,给类变量grade赋值
// s1.grade = 2; //也可以通过对象来访问类变量,不过不推荐这麽做
s1.name = "小明"; //学生对象1实例变量赋值
s2.name = "小红"; //学生对象2示例变量赋值
System.out.println("我是" + Student.grade +"年级的" + s1.name); //输出学生对象1和学生对象2的信息
System.out.println("我是" + Student.grade +"年级的" + s2.name);
}
}
像这种访问方式是错误的,因为实例变量独属于每个对象,只通过类名怎么知道你是想访问哪个对象呢~
public class Student2 {
public static int number; //记录已经创建多少个学生对象
public Student2() {
//在同一个类中,访问自己类的类变量可以不写类名,在别的类中需要写类名
number++; //每次调用构造函数,都记录下来
}
}
public class StaticDemo2 {
public static void main(String[] args) {
Student2 s1 = new Student2();
Student2 s2 = new Student2();
Student2 s3 = new Student2();
System.out.println("我已经创建了" + Student2.number + "个学生对象啦");
}
}
运行结果:
类方法不可以访问实例方法和实例变量,但是实例方法可以访问类方法和类变量
public class Student3 {
double score; //分数
public static void HelloWorld(){ //Static修饰的成员方法——类方法
System.out.println("HelloWorld!");
}
public void Pass(){ //没用Static修饰的成员方法——实例方法
System.out.println(this.score >= 60? "及格" : "不及格");
}
}
public class StaticDemo3 {
public static void main(String[] args) {
//通过类名访问实例方法,推荐
Student3.HelloWorld();
//通过对象访问实例方法.不推荐
Student3 s = new Student3();
s.HelloWorld();
//通过类名访问实例方法,报错
// Student3.Pass();
}
}
其实main方法就是一个类方法,当我们用java命令执行程序的时候,虚拟机会用当前类直接.main()方法,也就是说 java test == test.main(), 那么main方法括号里的字符串数组是干什么的呢?:,这个数组实际上是用来接收数据的,并且我们也可以去使用这个数组里的数据(如果有的话),我们可以在控制台执行class文件的时候传入一些参数给main方法使用,比如现在有这麽一串代码:
public class Test {
public static void main(String[] args) {
for (String arg : args) {
System.out.println(arg);
}
}
}
在控制台编译执行并传入数据给它:
如果需要一个类只存一些需要重复使用的方法,那么就可以创造一个专门提供这些方法的工具类,在类里面创造需要的类方法,需要使用该方法的时候直接类名.类方法就可以很方便的使用了。例如有多个类都需要创建指定位数验证码时,就可以 创建一个工具类专门存放生成随机验证码方法以供调用:
假设现在有一个方法1需要创建一个四位验证码,另一个方法2需要创建一个六位验证码,为了提高代码复用,减少重复代码,我们就可以专门为创建验证码这个方法设计一个方法类,放在工具类中以供调用:
方法1代码:
public class Demo1 {
//需要创建四位验证码
public void CreateCode(){
System.out.println(MyUtil.CreateCode(4));
}
}
方法2代码:
public class Demo2 {
//需要创建六位验证码
public void CreateCode(){
System.out.println(MyUtil.CreateCode(6));
}
}
工具类代码:
import java.util.Random;
public class MyUtil { //专门存放需要重复使用的方法的工具类
public static String CreateCode(int digit) { //验证码随机生成方法,作为类方法提高复用性
Random r = new Random();
String numbers = "1234567890abcdefghijklmnopqistuvwxyzABCDEFGHIJKLMNOPQISTUVWXYZ"; //字符池
StringBuilder code = new StringBuilder();
while(digit-- != 0){ //传入的形参控制位数
code.append(numbers.charAt(r.nextInt(0, 63)));
}
return code.toString();
}
}
测试:
public class Test {
public static void main(String[] args) {
Demo1 d1 = new Demo1();
Demo2 d2 = new Demo2();
d1.CreateCode();
d2.CreateCode();
}
}
运行结果:
静态代码块:
public class Block {
static int age = 18; //类变量
static{ //静态代码块,只会在类加载时执行一次
System.out.println("静态代码块被执行");
}
}
测试:
public class Test {
public static void main(String[] args) {
System.out.println(Block.age); //访问Block类的类变量,会先加载Block类
System.out.println(Block.age); //访问三次
System.out.println(Block.age);
}
}
结果:
虽然访问了三次类变量,但是静态代码块只在第一次访问加载时执行了一次
实例代码块:
public class Block {
String name; //实例变量
{ //实例代码块,每次创建对象在构造器前执行一次
System.out.println("实例代码块执行");
}
public Block() {
System.out.println("无参构造器执行");
}
public Block(String name) {
System.out.println("有参构造器执行");
}
}
测试:
public class Test {
public static void main(String[] args) {
Block b1 = new Block(); //创建对象并调用无参构造器
Block b2 = new Block("小明"); //创建对象并调用有参构造器
}
}
结果:
每次创建对象时,都会在调用构造器之前执行一次实例代码块
虽然实例代码块可以给示例变量赋初值,但是意义不大,因为实例代码块不能传参,所有赋初值的实例变量都是一个值,所以一般不会去使用实例代码块给实例变量赋初值,但是可以用实例代码块记录日志之类的,比如每次有人创建对象,就可以在实例代码块记录一下
单例设计模式设计一个类:
public class SingleCase {
private static SingleCase s = new SingleCase(); //2、定义一个类变量记住一个类对象
private SingleCase(){} //1、私有类的构造器
public static SingleCase getObject(){ //定义一个类方法返回类对象
return s;
}
}
测试:
public class Test {
public static void main(String[] args) {
// SingleCase s = new SingleCase(); 无法再通过原来的方法创建该类对象
SingleCase s1 = SingleCase.getObject(); //但是可以通过类方法调用类变量返回一个对象
SingleCase s2 = SingleCase.getObject(); //因为类变量只会在类加载的时候创建一次,所以通过这种方法创建的类对象都是同一个
System.out.println(s1);
System.out.println(s2);
}
}
运行结果:
俩个类对象的地址都是一样的,说明它们引用的是同一个对象
这是官方提供的Runtime类,可以看到它就是使用的单例设计模式来设计的
比如说我们常用到的任务管理器就是单例设计模式,不管启动多少次任务管理器,它都只会打开那一个任务管理器。在只需要一个对象即可解决问题时,就可以使用单例设计模式来设计,即可以避免内存浪费
单例设计模式不止一种:
像刚才代码演示的单例设计模式只是其中一种,称为饿汉式单例设计模式,除此之外还有懒汉式单例模式、双检索等等.......