第九章

类变量与类方法

9.1 类变量

9.1.1 类变量的内存刨析:


static变量保存在class实例的尾部,
JDK7以上的版本,静态域储存于定义类型的Class对象中,Class对象如同队中其他对象一样,存在于GC堆中。
基本共识:
1、static变量是同一个类所有对象的共享
2、static类变量,在类加载的时候就生成了。

9.1.2类变量介绍

类变量概念:
类变量也叫做静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都i是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量,从上面的内存刨析图可以看出。

类变量定义:
访问修饰符 static 数据类型 变量名;{推荐使用}
static 访问修饰符 数据类型 变量名;

类变量的访问:
类名.类变量名{推荐使用}
对象名.类变量名 【静态变量的访问修饰符的访问权限和范围 与 普通属性一样的】

public class ChildGame {public static void main(String[] args) {//类名.类变量名//因为static是随着类的加载而创建的,所以即使没有创建对象实例也可以用类名去访问System.out.println(A.name);//对象名.类变量名A a = new A();System.out.println(a.name);}
}
class A{//类变量的访问也要遵循访问修饰符的访问权限//如果name的访问修饰符是privat,则在上面的类中的访问方法就会报错public static String name = "猪猪";
}

9.1.3 类变量的细节

1、什么时候使用类变量
当我们需要让某个类的所有对象都共享一个变量的时候,可以考虑使用类变量(静态变量),比如:定义学生类,统计所有学生交多少钱的时候。Student(name,static fee)

2、类变量与实例变量(普通变量)的区别
类变量是该类的所有对象共享的,而实例变量是每个对象独享的

3、加上static称为类变量或者静态变量,否则称为实例变量/普通变量/非静态变量

4、类变量的访问可以通过: 类名.类变量名【推荐使用】 或者 对象名.类变量名

5、实例变量不能通过 类名.类变量名 方式访问

6、类变量是在类加载的时候就初始化了,也就是说,即使没有创建对象,只要是类以及加载了,就可以使用类变量。

7、类变量的生命周期是随类的加载开始,随着类的消亡而销毁

public class ChildGame {public static void main(String[] args) {//类名.类变量名//因为static是随着类的加载而创建的,所以即使没有创建对象实例也可以用类名去访问System.out.println(A.name);//因为age是实例变量所以不能用 类名.类变量名访问,所以会报错System.out.println(A.age);//错的//对象名.类变量名A a = new A();System.out.println(a.name);}
}
class A{//类变量的访问也要遵循访问修饰符的访问权限//如果name的访问修饰符是privat,则在上面的类中的访问方法就会报错public static String name = "猪猪";//实例变量/普通变量/public int age = 10;
}

9.2类方法

9.2.1 类方法基本介绍

类方法又叫做静态方法

类方法定义形式:
访问修饰符 static 数据返回类型 方法名(){ }【推荐使用】
static 访问修饰符 数据返回类型 方法名(){ }

类方法的调用:
类名.类方法名 或者 对象名.类方法名

public class StaticMethod {public static void main(String[] args) {//创建2个学生对象,交学费Student tom = new Student("tom");tom.payFee(100);//用对象名.类方法名 调用//Student.payFee(100);//用类名.类方法名 调用Student jack = new Student("jack");jack.payFee(200);//Student.payFee(200);Student.showFee();//用类名去调用显示费用的方法,因为fee是定义的一个类变量,//所以每一次调用的时候,调用的都是同一个地址的类变量,所以每一次调用,值都会变化}
}
class Student{private String name;//普通成员//定义一个静态变量,来累积学生的学费private static double fee = 0;public Student(String name) {this.name = name;}//1、当方法使用static的时候,表示该方法就是静态方法//2、静态放啊发可以访问静态变量public static void payFee(double fee){Student.fee += fee;//累积到静态变量fee中}public static void showFee(){System.out.println("总学费="+Student.fee);}
}

9.2.2 类方法使用场景

1、当方法中不涉及任何与对象相关的成员,则可以将方法设计成静态方法,提高开发效率。比如工具类中的方法 utils、Math类、Arrays类等等:以下是其Math源码:

2、当程序员自己开发中,通常会将一些通用的方法,去设计成静态方法,这样我们不需要创建对象就可以直接使用的工具方法,例如打印一维数组、冒泡排序,完成某个计算任务等

        System.out.println(Student.sum(20,30));}
}
class Student{//获取两个数的和的方法,将其定义成一个static方法,然后可以直接调用public static double sum(double n1,double n2){return n1+n2;}

9.2.3 类方法的细节

1、类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区
注:类方法 中没有this的参数; 普通放啊发中隐含有this参数

2、类方法 可以通过类名调用,也可以通过对象名调用

3、普通方法和对象有关,需要通过对象名调用,比如: 对象名.方法名(参数),不能通过类名调用

4、类方法中不允许使用和对象有关的关键字,比如this和super,普通方法(成员方法)可以

5、类方法(静态方法)中 只能访问 静态变量 或者静态变量

6、普通成员方法,既可以访问普通方法(方法),也可以访问静态变量(方法)

总结:静态方法(类方法) 只能访问静态成员和静态方法,非静态的方法(普通方法),可以访问静态成员和非静态成员(必须遵守访问权限

9.3 main语法

9.3.1main语法说明

main方法的形式:
public static void main(String[ ] args){ }
注:main方法是由虚拟机去调用的
解释:
1、public 是因为当Java虚拟机要去调用main()方法的时候,必须要由访问权限,所以必须是public公共的

2、static 是因为 当Java虚拟机去调用的时候,是不需要创建对象的,所以将其定义成一个静态方法,可以直接被Java虚拟机调用

3、main()方法接收的是String类型的数组参数,该数组中保存执行Java命令时,传递给所运行的类的参数

4、String[ ] 数组的参数值,是在 Java 执行程序的时候所传进去的 在命令行中
例: Java 执行程序 参数1 参数2 参数3

9.3.2 main方法特别说明

1、在main()方法中。我们可以直接调用main方法所在类的静态方法或者静态属性
2、但是,不能直接访问该类中的非静态成员,必须要创建一个对象后,才可以通过对象去访问类中的非静态成员。毕竟 main()方法是一个静态方法

代码:

public class Main01 {//静态变量/成员private static String name = "小王";//静态方法public static void hi(){System.out.println("我是静态方法hi");}//普通变量/成员private int age = 21;//普通方法public void ok(){System.out.println("我是普通方法ok");}public static void main(String[] args) {//因为main方法时静态的,所以可以访问静态变量、静态方法System.out.println("name= "+name);hi();//访问普通变量// System.out.println("age = "+age);//错误//访问普通方法//  ok();//错误//因为main()方法是静态方法,所以不能直接访问该类的非静态成员//所以直接会报错,要访问必须创建一个类对象,用对象去调用访问Main01 main01 = new Main01();System.out.println("age= "+main01.age);main01.ok();}
}

输出:

9.3.3 main方法动态传参(idea)

在 9.3.1 中的 4 那里,用的是命令行去传参的,而在平时的工作或者开发过程中都是用工具(idea、eclipse等),所以我们看一下在idea中,如何去传参
首先先输入输出的代码:

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

当直接运行这段代码的时候,当然不会输出任何值,传参方式如下:


输出:

9.4 代码块

9.4.1 代码块基本介绍

基本概念:
代码化块又称为初始化块,属于类中的成员【即 是类的一部分】,类似于方法,将逻辑语句封装在方法体中,通过{ }包装起来,
但是,和方法又不同,代码块没有方法名,没有返回,没有参数,只有方法体(也就是 只有方法体的方法代码块),而且不用通过对象或者类去显式调用,而是在加载类的时候,或者创建对象的时候去隐式调用的

基本语法:
[修饰符] {
代码
};

注:
1、修饰符 是可以选择的 , 要写的话,也只能写static

2、代码块分为两类,使用static 修饰的叫静态代码块,没有static修饰的是普通代码块/非静态代码块

3、逻辑语句可以为任何的逻辑语句(输入、输出、方法调用、循环、判断等)

4、 ;号可以写也可以省略

9.4.2代码块的使用

1、相当于另外一种形式的构造器(对构造器的补充机制),可以作初始化的操作

2、使用场景:如果多个构造器中都由重复的语句,可以抽取到初始化块中,提高代码的重用性。

案例:
创建一个电影类,属性如下:创建三个构造器,当创建一个对象的时候,无论使用那个构造器都会输出以下三句话:
System.out.println(“电影名字:”+name);
System.out.println(“电影价格:”+price);
System.out.println(“电影导演:”+actor);

第一种方法:
直接在每一个构造器里面去输出三句话。

public class Block01 {public static void main(String[] args) {Movie movie = new Movie("反贪5");}
}class Movie{private String name;private int price;private String actor;public Movie(String name) {System.out.println("电影名字:"+name);System.out.println("电影价格:"+price);System.out.println("电影导演:"+actor);this.name = name;}public Movie(String name, int price) {System.out.println("电影名字:"+name);System.out.println("电影价格:"+price);System.out.println("电影导演:"+actor);this.name = name;this.price = price;}public Movie(String name, int price, String actor) {System.out.println("电影名字:"+name);System.out.println("电影价格:"+price);System.out.println("电影导演:"+actor);this.name = name;this.price = price;this.actor = actor;}
}

这种方法可以在每一个构造器中去输出这三句话,但是随着构造器越多,代码的复杂度就月大,看起来就很不清晰。

第二种方法:
鉴于避免以上的代码冗余,所以我们可以将其共有部分放在代码块中,当创建对象的时候,就会自动的调用代码块。

public class Block01 {public static void main(String[] args) {Movie movie = new Movie("反贪5");Movie movie1 = new Movie("你好,李焕英", 40, "weizhi");}
}class Movie{private String name;private int price;private String actor;{System.out.println("电影屏幕打开");System.out.println("播放广告");System.out.println("开始播放电影");};public Movie(String name) {System.out.println("Movie(String name)构造器被调用");this.name = name;System.out.println(toString());System.out.println("========================");}public Movie(String name, int price) {System.out.println("Movie(String name, int price)构造器被调用");this.name = name;this.price = price;System.out.println(toString());}public Movie(String name, int price, String actor) {System.out.println("Movie(String name, int price, String actor)构造器被调用");this.name = name;this.price = price;this.actor = actor;System.out.println(toString());}@Overridepublic String toString() {return "Movie{" +"name='" + name + '\'' +", price=" + price +", actor='" + actor + '\'' +'}';}
}
输出:电影屏幕打开
播放广告
开始播放电影
Movie(String name)构造器被调用
Movie{name='反贪5', price=0, actor='null'}
========================
电影屏幕打开
播放广告
开始播放电影
Movie(String name, int price, String actor)构造器被调用
Movie{name='你好,李焕英', price=40, actor='weizhi'}

由这个方法我们可以看出,当一个对象被创建的时候,代码块将会被执行,由输出我们可以看出,代码块的内容被优先于调用,

通过两种方法的比较,我们可以看出,使用代码块,可以提高代码的复用性,以及可以减少程序的复杂度和清晰度。

9.4.3 注意事项和细节!!

1、static代码块也叫静态代码块,作用是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次,如果是普通的代码块,则每创建一个对象就执行。

2、类什么时候被加载[重要]!!!!!!

①创建对象实例时(new 一个对象的时候)

②创建子类对象实例时,父类也会被加载(由下面案例可知,先加载父类再加载子类)

③使用类的静态成员时(静态属性,静态方法)

(通过输出语句来判断类是否被加载,以下是 static 代码块演示):

public class Block02 {public static void main(String[] args) {//1.创建实例对象时(new)AA aa = new AA();//执行一次//2.创建子类对象实例时,父类也会被加载(先加载父类,再加载子类,所以先输出BB,再输出AA)AA aa2 = new AA();//因为static代码块只会被执行一次,所以在这里不会再被执行//3.使用类的静态成员时(静态属性,静态方法)System.out.println(Cat.age);//(先加载父类,再加载子类)}
}
class Animal{static {System.out.println("Animal的静态代码块1被执行");}
}
class Cat extens Animal{public static int age = 3;static {System.out.println("Cat的静态代码块1被执行");}
}
class AA extends BB{//静态代码块static {System.out.println("AA的静态代码块1被执行");}
}
class BB{static {System.out.println("BB的静态代码块1被执行");}
}
输出:BB的静态代码块1被执行
AA的静态代码块1被执行
Animal的静态代码块1被执行
Cat的静态代码块1被执行
3

3、普通代码块,在创建对象实例时,会被隐式调用,每被创建一次就被调用一次

public class Block02 {public static void main(String[] args) {DD dd = new DD();DD dd1 = new DD();//静态代码块只执行一次,普通的创建一个对象就执行一次}
}
class DD{public static int n1 = 222;static {//静态代码块System.out.println("DD的静态代码块1被执行");}{//普通代码块System.out.println("DD的普通代码块被执行");}
}
输出:DD的静态代码块1被执行
DD的普通代码块被执行
DD的普通代码块被执行

如果是只使用类的静态成员,则普通代码块不会被执行(因为普通代码块是构造器的补充,如果构造器被调用(new 一个对象),则普通代码块会被执行)

public class Block02 {public static void main(String[] args) {System.out.println(DD.n1);//静态代码块一定会被输出,// 普通代码块不会执行,创建对象了(new一个对象)才能被执行,每创建一个对象就会被调用一次}
}
class DD{public static int n1 = 222;static {//静态代码块System.out.println("DD的静态代码块1被执行");}{//普通代码块System.out.println("DD的普通代码块被执行");}
}
输出:
DD的静态代码块1被执行
222

注:
1)、static代码块是类加载时,执行,只会被执行一次
2)、普通代码块是在创建对象时调用的,创建一次,调用一次
3)、类加载的三种情况,要记住

4、创建一个对象时,在一个类中的调用顺序(重点、难点!!!)

调用静态代码块和静态属性初始化(注:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)主要是因为是类加载时被调用

public class Block03 {public static void main(String[] args) {A a = new A();//调用顺序:(1)getN1被调用(2)A 静态代码块01,//static的优先级一样,所以按照定义顺序去调用}
}
class A{//静态属性初始化private static int n1=getN1();static {//静态代码块System.out.println("A 静态代码块01");}public static int getN1(){System.out.println("getN1被调用");return 100;}
}
输出:
getN1被调用
A 静态代码块01

调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果由多个普通代码块和多个普通属性初始化,则按定义顺序调用)是用对象去加载

public class Block03 {public static void main(String[] args) {A a = new A();//调用顺序:(1)getN2被调用(2)A 的普通代码块01//普通代码块的优先级一样,所以按照定义顺序去调用}
}
class A{private int n2 = getN2();//普通属性初始化{System.out.println("A 的普通代码块01");}public int getN2(){//普通方法/非静态方法System.out.println("getN2被调用");return 200;}
}
输出:
getN2被调用
A 的普通代码块01

最后再调用构造器(综合代码)

public class Block03 {public static void main(String[] args) {A a = new A();//调用顺序:(1)getN1被调用(2)A 静态代码块01(3)getN2被调用(4)A 的普通代码块01(5)A的无参构造器被调用//static的优先级一样,所以按照定义顺序去调用}
}
class A{//构造器,最后被调用public A() {System.out.println("A的无参构造器被调用");}//普通属性初始化private int n2 = getN2();//普通代码块{System.out.println("A 的普通代码块01");}public int getN2(){//普通方法/非静态方法System.out.println("getN2被调用");return 200;}//静态属性初始化private static int n1=getN1();static {//静态代码块System.out.println("A 静态代码块01");}public static int getN1(){System.out.println("getN1被调用");return 100;}
}
输出:
getN1被调用
A 静态代码块01
getN2被调用
A 的普通代码块01
A的无参构造器被调用

总结:当在 “一个类” 中创建一个对象实例的时候,调用顺序是:静态(按定义顺序)>非静态(按定义顺序)>构造器,静态是与类

5、构造器 的最前面其实隐含了 super()和 调用普通代码块,静态(static)相关的代码块,属性初始化,在类加载时,就i执行完毕,因此是优先于 构造器和普通代码块的

class A{
public A(){
//这里由隐藏的执行要求
//(1)super()
//(2)调用本类的普通代码块
}
}

public class Block04 {public static void main(String[] args) {new B();}
}
class C{{System.out.println("C的普通代码块");}public C(){//这里其实是隐藏了两个方法的//(1)super();//(2)调用本类的普通代码块System.out.println("C的无参构造器");}
}
class B extends C{{//普通代码块System.out.println("B的普通代码块");}private static String n1 =getN1();//静态属性初始化public static String getN1(){System.out.println("B的static的n1被调用");//静态代码块在对象加载的时候就被调用,所以先输出return n1;}public B(){//这里其实是隐藏了两个方法的//(1)super();//(2)调用本类的普通代码块System.out.println("B的无参构造器");}
}
输出:
B的static的n1被调用
C的普通代码块
C的无参构造器
B的普通代码块
B的无参构造器

6、我们看一下创建一个子类对象时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:

①父类的静态代码块和静态属性(优先级一样,按定义顺序执行)

②子类的静态代码块和静态属性(优先级一样,按定义顺序执行)

③父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)

④父类的构造器

⑤子类的普通代码块和普通方法属性初始化(优先级一样,按定义顺序执行)

⑥子类的构造器

例:分析下面代码的输出

public class Block05 {public static void main(String[] args) {new B02();//先加载父类A02 再加载子类B02 static静态方法是在类加载的时候就调用的}
}
class A02{//父类private static int n1 = getVal01();static {System.out.println("A02的一个静态代码块..");//(2)}{System.out.println("A02的一个普通代码块..");//(5)}public int n3=getVal02();public static int getVal01(){System.out.println("getVal01");//(1)return 10;}public int getVal02(){System.out.println("getVal02");//(6)return 10;}public A02() {//构造器//隐藏了//(1)super();//(2)本类的普通代码块和普通属性的初始化System.out.println("A02的构造器");//(7)}
}
class B02 extends A02{private static int n3 =getVal03();static {System.out.println("B02的一个静态代码块..");//(4)}public int n5 = getVal04();{System.out.println("B02的一个普通代码块..");//(9)}public static int getVal03(){System.out.println("getVal03");//(3)return 10;}public int getVal04(){System.out.println("getVal04");//(8)return 10;}public B02(){//隐藏了//(1)super();//(2)本类的普通代码块和普通属性的初始化System.out.println("B02的构造器");//(10)}
}
输出:
getVal01
A02的一个静态代码块..
getVal03
B02的一个静态代码块..
A02的一个普通代码块..
getVal02
A02的构造器
getVal04
B02的一个普通代码块..
B02的构造器

7、静态代码块只能调用静态成员(静态属性和静态方法)

9.4.4练习题

A01:分析下列代码

ic class Block06 {public static void main(String[] args) {System.out.println("total="+A01.total);//首先先加载A01,所以A01的static被调用System.out.println("total="+A01.total);//因为static只会被调用一次,所以第二次现在不会调用,在第一次的时候total以及被赋值了}
}
class A01{public static int total;static {total = 100;//100返回上去(2)(3)System.out.println("in static block!");//(1)}
}
输出:
in static block!
total=100
total=100

第二条语句只输出total的值,因为static只会被调用一次,所以第二次现在不会调用,在第一次的时候total以及被赋值了

A02:分析下列代码的输出

public class Block07 {public static void main(String[] args) {Test test = new Test();//1、类加载}
}
class Test{Sample sam1 =  new Sample("sam1成员初始化");//9、static Sample sam = new Sample("静态成员sam初始化");//2、static {System.out.println("static块执行");//5、if (sam == null){//6、在2那句sam已经被赋值了,所以sam不为nullSystem.out.println("sam is null");}}Test(){//7、//隐含了super(),父类是object类,所以没有输出,不考虑//8、隐含了普通方法System.out.println("Test默认构造函数被调用");//12}
}
class Sample{Sample(String s){//3、//10、System.out.println(s);//4、//11、}Sample(){System.out.println("Sample默认构造器被调用");}
}
输出:静态成员sam初始化
static块执行
sam1成员初始化
Test默认构造函数被调用

9.3单例设计模式

9.3.1设计模式概念

设计模式是在大量的实践中总结和理论化之后优选的代码结构、编码风格、以及解决问题的思考方式。设计模式就像是经典的棋谱,不同的棋谱、不同的棋局,我们用不同的棋谱,免去我们自己再去思考和摸索。

9.3.2 单例模式

1.单例模式,就是采取一定的方法保证再整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法

2.单例模式有两种:①饿汉式 ②懒汉式

9.3.3 单例模式的应用实例

9.3.3.1 饿汉式

步骤:
① 将构造器私有化,防止用户直接new一个对象
② 在类的内部去创建对象
③ 向外暴露一个静态的公共方法
④ 代码实现

例:要求:创建一个GirlFriend类,并且要求只能有唯一一个对象

//要求:创建一个GirlFriend类,并且要求只能有唯一一个对象
public class SingleTon01 {public static void main(String[] args) {//用类去调用一个对象System.out.println(GirlFriend.getInstance());//用方法去获取对象,判断是否是同一个对象GirlFriend gf1 = GirlFriend.getInstance();GirlFriend gf2 = GirlFriend.getInstance();System.out.println(gf1 == gf2);//true}
}class GirlFriend{private String name;// [// [单例模式----饿汉式 ]//步骤① 将构造器私有化,可有避免用户直接去new一个对象,那么就不是只有一个对象了private GirlFriend(String name) {this.name = name;}//步骤② 在类的内部创建一个对象,为了保证能够使用,其对象将其设置为static静态的private static GirlFriend gf = new GirlFriend("江仔");//步骤③ 提供一个公共的static方法,去返回 gf对象public static GirlFriend getInstance(){return gf;}//用toString方法去显示对象@Overridepublic String toString() {return "GirlFriend{" +"name='" + name + '\'' +'}';}
}
输出:
GirlFriend{name='江仔'}
true

之所以叫做饿汉式,是因为一个对象没有被用,就已经随着类的加载被加载了,饿汉式可能造成创建了对象,到那时对象没有被使用

9.3.3.2 懒汉式

步骤:
1、构造器私有化
2、定义一个static静态属性
3、提供一个公共static方法,去返回一个Cat对象
4、只有当用户去使用getInstance()方法的时候,才会去返回一个cat对象, 后面继续调用的话,还是会返回上一次创建的cat对象,这样就保证了单例性

例:在程序的运行中,只能创建一个Cat对象

public class SingleTon02 {public static void main(String[] args) {//用类去调用其方法去创建对象System.out.println(Cat.getInstance());//用方法去创建对象Cat cat1 = Cat.getInstance();Cat cat2 = Cat.getInstance();System.out.println(cat1 == cat2);}
}
//在程序的运行中,只能创建一个Cat对象
//使用单例模式
class Cat{private String name;//步骤① 构造器私有化private Cat(String name) {this.name = name;}//步骤②定义一个static静态属性private static Cat cat;//没有初始化的时候,默认是null,当然也可以赋值为null//步骤③ 提供一个公共static方法,去返回一个Cat对象//步骤④ 只有当用户去使用getInstance()方法的时候,才会去返回一个cat对象,//       后面继续调用的话,还是会返回上一次创建的cat对象,这样就保证了单例性public static Cat getInstance(){if (cat == null){//如果还没有创建Cat对象就创建一个cat = new Cat("江仔");//将其步骤2定义的属性去创建其对象}return cat;}@Overridepublic String toString() {return "Cat{" +"name='" + name + '\'' +'}';}
}

懒汉式,主要就是用户要使用这个对象的时候才去创建这么一个对象去使用,不会造成资源浪费。

9.3.3.3 饿汉式、懒汉式区别

1、创建对象的时机不同:饿汉式是在类加载的时候就已经创建了对象实例,而懒汉式是在使用的时候才创建的

2、饿汉式不存在线程安全的问题,懒汉式存在线程问题

3、饿汉式存在浪费资源的可能性,因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是在使用的时候才创建,就不会存在这个问题

4、在我们javaSE标准类中,java.lang.Runtime就是经典的单例模式
Runtime源码如下:

public class Runtime {private static Runtime currentRuntime = new Runtime();/*** Returns the runtime object associated with the current Java application.* Most of the methods of class <code>Runtime</code> are instance* methods and must be invoked with respect to the current runtime object.** @return  the <code>Runtime</code> object associated with the current*          Java application.*/public static Runtime getRuntime() {return currentRuntime;}/** Don't let anyone else instantiate this class */private Runtime() {}

9.4 final关键字

9.4.1 final关键字概念

final可以修饰类、属性、方法和局部变量

应用场景:
1、在当一个类不希望被继承的时候,可以用final关键字修饰

2、当不希望类的某一个方法被子类重写或者覆盖的时候,可以用final关键字修饰

3、当不希望类的某个属性的值不被修改时,可以用final关键字修饰

4、当不希望某个局部变量被修改的时候,可以用final关键字修饰

9.4.2 final关键字细节

1、final修饰的属性又叫做常量,一般用 XX_XX_XX 命名,也就是命名时大写,且用下划线隔开
例: TAX_RATE = 10;

2、final修饰的属性在定义时,必须要赋初值,并且不能够再修改,赋值的位置以下之一:
定义时去赋值
②在构造器中去赋值
③在代码块中去赋值

3、如果final修饰的属性事静态的,则初始化的位置只能是在以下之一:

① 定义时
②在静态的代码块中

因为要遵循static关键字的语法使用规则,所以static的属性只能在static的方法中去使用赋值。

4、final类不能继承,但是可以实例化对象

5、如果类不是final类,但是含有final方法,则该方法虽然不能被重写,但是可以被继承

5、一般来说,如果一个类已经时final类了,就没有必要去再把方法修饰 成final方法
(因为类已经被final修饰了,那就整个类都不会被诶继承了,那么其他类自然也就不能够去重写类方法了,所以方法再用final修饰一次,有一点多余了)

6、final不能去修饰构造器

7、final关键字和static往往搭配使用,效率更高,不会导致类的加载(static是在确保不用创建对象的情况下,只要类被加载的,就可以去调用方法,两者结合的话,就不会导致类加载)

public class Final03 {public static void main(String[] args) {System.out.println(AAA.num);System.out.println(BBB.num1);}
}
class AAA{public static int num = 10;static {//用来测试会不会被类加载System.out.println("AAA的静态代码块被调用...");}
}
class BBB{public final static int num1 = 20;static {//用来测试会不会被类加载System.out.println("AAA的final 静态代码块被调用...");}
}
输出:
AAA的静态代码块被调用...
10
20

8、包装类(Integer、Double、String等都是final类,所以是不能被继承的)
源码:

9.4.3 final关键字练习题

/A01 编写一个程序,能够计算圆形的面积,要求圆周率为3.14,赋值的位置3个方式都写,并且时用对象去调用的/

package com.xioawang.final_;
/*编写一个程序,能够计算圆形的面积,要求圆周率为3.14,赋值的位置3个方式都写*/
public class FinalText1 {public static void main(String[] args) {Circle circle = new Circle();System.out.println(circle.are());}
}
class Circle{private double radius = 2;//半径先写定死,可以更改的//1、定义属性时去赋初值,并且通过对象去调用private final double PI ;//= 3.14;//2、构造器中去赋初值,并通过对象去调用public Circle() {// this.PI = 3.14;}//3、代码块中赋值{PI = 3.14;}public  double are(){return radius*radius*PI;}
}
输出:
12.56

/A02 编写一个程序,能够计算圆形的面积,要求圆周率为3.14,赋值的位置3个方式都写,并且时用类加载去调用/

public class FinalText2 {public static void main(String[] args) {System.out.println(Circle1.are());}
}
class Circle1{private static double radius = 2;private final static double PI ;static {PI=3.14;}public static double are(){return radius*radius*PI;}
}
输出:
12.56

类的篇幅就在这结束了吖,这是整个Java学习中的第九章哦,觉得还不错的可以查看我完整的Java笔记哦:
Java学习第二阶段(仍然在继续更新中~~~~)
Java学习第一阶段

Java 类详解 9章相关推荐

  1. java对字符串编码转换_处理字符串编码转换java类详解

    该字符串处理类包括将ISO-8859-1编码的字符串转换成GBK编码 .对输入的字符串进行一次编码转换,防止SQL注入和验证URL地址是否存在的方法. 字符串处理类(编码转化.SQL注入.URL) i ...

  2. java类详解_JAVA 内部类详解

    内部类分为四种: 非静态内部类 静态内部类 匿名类 本地类 非静态内部类 非静态内部类可以直接在一个类里面定义 所以实例化对象 的时候,必须建立在一个存在的对象 的基础上 语法: new 外部类(). ...

  3. Java中的Runtime类详解

    Java中的Runtime类详解 1.类注释 /**Every Java application has a single instance of class Runtime that allows ...

  4. JAVA的StringBuffer类详解

    JAVA的StringBuffer类详解 StringBuffer类和String一样,也用来代表字符串,只是由于StringBuffer的内部实现方式和String不同,所以StringBuffer ...

  5. java unsafe 详解_Java CAS操作与Unsafe类详解

    一.复习 计算机内存模型,synchronized和volatile关键字简介 二.两者对比 sychronized和volatile都解决了内存可见性问题 不同点: (1)前者是独占锁,并且存在者上 ...

  6. java的thread类_thread 类详解

    java.lang.Thread类详解 一.前言 位于java.lang包下的Thread类是非常重要的线程类,它实现了Runnable接口,今天我们来学习一下Thread类,在学习Thread类之前 ...

  7. java线程池ThreadPoolExecutor类详解

    线程池有哪些状态 1. RUNNING:  接收新的任务,且执行等待队列中的任务 Accept new tasks and process queued tasks  2. SHUTDOWN: 不接收 ...

  8. java configuration类_JAVA中的Configuration类详解

    本文主要研究的是java中的configuration类的用法,涉及maven自动加载,pom.xml配置和简单的java代码,具体如下. properties文件是java平台默认的配置文件格式,其 ...

  9. java之Pattern类详解

    在JDK 1.4中,Java增加了对正则表达式的支持. java与正则相关的工具主要在java.util.regex包中:此包中主要有两个类:Pattern.Matcher. Pattern  声明: ...

最新文章

  1. 收藏!深度学习计算机视觉模型解析!
  2. optee:kernel space调用user space进程时候的硬件行为
  3. opencv轻松入门面向python下载_OpenCV轻松入门:面向Python
  4. 【渝粤教育】电大中专电子商务网站建设与维护 (11)作业 题库
  5. LeetCode自我总结(对链表进行插入排序)
  6. Python 笔记(一)字典与json使用及注意点
  7. Java使用Selenium几个例子
  8. C#:获得本机IP地址
  9. Java贪吃蛇大作战
  10. 数学建模PPT(二)
  11. php输出一个直角三角形,php hypot()直角三角形斜边长度 is_infinite()是否为无限值...
  12. 计算机组成原理保姆级复习资料
  13. python中round函数参数有负数_Python中round函数使用注意事项
  14. MCU实现低功耗注意事项
  15. 【每日分享】我做程序员那些年犯下的罪,此时此刻我自己的笑出猪叫~
  16. vue将文件流转成xlsx文件
  17. linux命令说法错误的是什么,有关Linux 中的命令,下面那些说法是错误的? (多选)...
  18. Pasqal首席技术官:模拟量子计算率先为工业带来量子优势
  19. C# 中where关键字详解
  20. Android ley hash的生成

热门文章

  1. vue 取数组第一个值_vue里如何取出数组中的数组(的某一个元素)
  2. 阿里云配置服务器,短信,域名
  3. 并查集巧妙用法(codeforces)C. Destroying Array
  4. 中国石油大学《微观经济学》在线考试
  5. vue电商实战-黑马-01
  6. amigo幸运字符什么意思_史上最全python字符串操作指南
  7. Oracle数据库(五)用户 ,角色,权限
  8. 130行Python代码模仿“蚂蚁呀嘿”特效,太魔性了!
  9. 如何下载网页上的视频和flash的方法
  10. ServiceNow CSA管理员考试(ServiceNow Fundamentals (On Demand) Paris)