1、使用static修饰属性,即静态变量,按照static是否修饰属性,可以分为静态属性和非静态属性(实例变量)。
(1)非静态属性:创建类的多个对象,每个对象都独立拥有类中的一套非静态变量,当修改其中一个对象的非静态属性时,不会改变其他对象的属性值;
(2)静态属性:创建类的多个对象,多个对象共享同一个静态变量,当通过某个对象修改静态变量值后,其他对象调用该静态变量时,值是被修改过的;
- 静态变量随着类的加载而加载,可以通过“类.静态变量”来进行调用或赋值
- 静态变量早于对象的加载
- 类只会加载一次,因此静态变量也只会加载一次,存在方法的静态区中
2、static修饰方法,即静态方法
- 静态变量随着类的加载而加载,可以通过“类.静态方法”来进行调用
- 在静态方法中,不能使用this、super关键字,不能调用静态结构(方法或属性),可以调用静态结构(方法或属性)
3、static练习题
public class exe08 {
public static void main(String[] args) {
Account a1 = new Account();
Account a2 = new Account("900990",10000);
//直接"类名.静态方法名"来设置static变量值
Account.setInterestRate(0.012);
Account.setMinAmount(100);
System.out.println(a1);
System.out.println(a2);
//采用对象获取static方法
System.out.println(a1.getMinAmount()); //100.0
System.out.println(a2.getInterestRate()); //0.012
}
}
//Account类的创建
class Account{
private int id;
private String password = "000000";
private double balance;
//声明为static静态变量
private static double interestRate;
private static double minAmount = 1.0;
//用于自动生成账户id号
private static int init = 1001;
public Account(){
//账号自动加一
id = init++;
}
public Account(String password,double balance){
//有参构造器id也要自动加一
id = init++;
this.balance = balance;
this.password = password;
}
//相关set、get方法 对应静态变量的相关方法也是静态方法
public int getId() {
return id;
}
public String getPassword() {
return password;
}
public double getBalance() {
return balance;
}
public static double getInterestRate() {
return interestRate;
}
public static double get() {
return minAmount;
}
public void setBalance(double balance) {
this.balance = balance;
}
public static void setInterestRate(double interestRate) {
Account.interestRate = interestRate;
}
public static double setInterestRate(){
return interestRate;
}
public static void setMinAmount(double minBalance) {
Account.minAmount = minBalance;
}
public static double getMinAmount(){
return minAmount;
}
}
4、单例(singleton)设计模式
单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。如果我们要让类在一个虚拟机中只能产生一个对象,我们首先必须将类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象。因为在类的外部开始还无 法得到类的对象,只能调用该类的某个静态方法以返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以,指向类内部产生的该类对象的变量也必须定义成静态的。
饿汉式单例设计模式
public class Singleton1Test {
public static void main(String[] args) {
Singleton1 s1 = Singleton1.getInstance();
Singleton1 s2 = Singleton1.getInstance();
System.out.println(s1 == s2); //true
}
}
//
//class Singleton1 {
// // 1.私有化构造器 类外部无法创建该类的实例
// private Singleton1() {
// }
//
// // 2.内部创建当前类的实例
// // 4.此实例也必须静态化
// private static Singleton1 single = new Singleton1();
//
// // 3.提供公共的静态的方法,返回当前类的对象
// public static Singleton1 getInstance() {
// if (single == null) { //为空则提供一个新对象
// single = new Singleton1();
// }
// return single; //否则返回该对象
// }
//}
//懒汉式单例设计 (不安全的)
class Singleton1 {
// 1.私有化构造器
private Singleton1() {
}
// 2.内部提供一个当前类的实例
// 4.此实例也必须静态化
private static Singleton1 single;
// 3.提供公共的静态的方法,返回当前类的对象
public static Singleton1 getInstance() {
if(single == null) {
single = new Singleton1();
}
return single; } }
5、代码块的使用
(代码块先于构造器的执行)
作用:用来初始化类、对象
划分:只能用static修饰,分为static代码块和非static代码块
(1)static代码块
- 可以有输出语句
- 随着类的加载而执行(static方法和static属性是随着类的加载而加载),而且只执行一次
- 可以有多个static代码块,按照声明的先后顺序执行
- static代码块的执行优先于非static代码块的执行
- static代码块中只能调用static型的属性或方法,不能调用非static的结构
- 作用:初始类的信息
(2)非static代码块
- 可以有输出语句
- 随着对象的创建而执行,每创建一次对象就执行一次非static代码块
- 可以调用static或者非static的属性和方法(即可以修改static属性值)
- 作用:可以在创建对象时,对对象进行初始化操作
public class CodeBlockTest {
public static void main(String[] args) {
String str1 = Animal.str; //执行static代码块
System.out.println(Animal.str);
System.out.println(Animal.info()); //没有执行static代码块
Animal dog = new Animal(); //执行非static代码块
System.out.println(dog.name); //在非static代码块中对name做了初始化
System.out.println(dog.str); //在非static代码块中修改了static变量
System.out.println(Animal.str); //输出在非代码块中修改过的static属性值
}
}
class Animal{
//属性
String name;
int age;
static String str = "未修改的str";
//构造器
public Animal(){
}
public Animal(String name,int age){
this.name = name;
this.age = age;
}
//代码块
//用satic修饰的代码块
static {
System.out.println("static codeBlock");
str = "在static代码块修改过的str";
}
static {
System.out.println("static codeBlock 1");
}
//非static代码块
{
System.out.println("non static codeBlock");
str = "在非static代码块中修改过的str";
name = "旺财";
}
//方法
public void play(){
System.out.println("playing...");
}
//toString()方法的重写
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//静态方法
public static String info(){
return "It's a kind of animal";
}
}
6、代码块练习题
(先执行父类(先执行所有static代码块),再执行子类(先执行非static代码块,后执行构造器))
练习题1:
//先执行父类后执行子类 先执行static代码块 后执行非static代码块 在执行构造器
class Root {
static {
System.out.println("Root的静态初始化块");
}
{
System.out.println("Root的普通初始化块");
}
public Root() {
System.out.println("Root的无参数的构造器");
}
}
class Mid extends Root {
static {
System.out.println("Mid的静态初始化块");
}
{
System.out.println("Mid的普通初始化块");
}
public Mid() {
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();
//new Leaf();
}
}
输出:
练习题2:
class Father {
static {
System.out.println("11111111111");
}
{
System.out.println("22222222222");
}
public Father() {
System.out.println("33333333333");
}
}
public class Son extends Father {
static {
System.out.println("44444444444");
}
{
System.out.println("55555555555");
}
public Son() {
System.out.println("66666666666");
}
public static void main(String[] args) { // 由父及子 静态先行
new Son();
System.out.println("************************");
new Son();
System.out.println("************************");
new Father();
}
}
输出:
7、属性赋值顺序
(1)默认初始化赋值(默认赋值)
(2)显式赋值(类中初始化时赋值)
(3)代码块赋值
(4)构造器初始化(构造器内部赋值)
(5)“对象.属性” “对象.方法” 赋值
执行顺序:(1)- (2)/(5)- (3)-(4)
8、final关键字
- 用来修饰类,此类不能被继承,比如String、System、StringBuffer类
- 用来修饰方法,此方法不能被重写,比如Object类的getClass()方法
- 用来修饰变量,此变量成为常量,此时可以赋值的位置可以是:显式赋值、代码块中赋值、构造器中赋值。(不能采用“对象.属性” “对象.方法”来赋值,因为在使用构造器声明对象后,推空间里就必须有final修饰的变量的值存在,而方法此时还未被调用)
class finalT{
//显式赋值
final int num1 = 1;
final int num2;
final int num3;
//代码块中赋值
{
num2 = 2;
}
//构造器中赋值
public finalT(){
num3 = 3;
}
//final修饰的方法
final public void print(){
System.out.println("yeah");
}
}
- static final修饰的属性称为全局常量