Java学习
1 static静态
总结:有static修饰的属性/方法 与类同时出现
- static 用来修饰的结构:属性、方法; 代码块、内部类;
修饰属性
-
static修饰属性
变量的分类
-
按照数据类型:基本数据类型、引用数据类型
-
按照类中声明的位置:
成员变量:按照是否使用static修饰进行分类:
使用static修饰的成员变量:静态变量、类变量
不使用static修饰的成员变量:非静态变量、实例变量 局部变量:方法内、方法形参、构造器内、构造器形参、代码块内等。
-
-
静态变量与实例变量:
① 个数
静态变量:在内存空间中只有一份,被类的多个对象所共享。
实例变量:类的每一个实例(或对象)都保存着一份实例变量。
② 内存位置
静态变量:存放在堆空间
实例变量:存放在堆空间的对象实体中。
③ 加载时机
静态变量:随着类的加载而加载,由于类只会加载一次,所以静态变量也只有一份。
比如
private static int init = 1001; //只会加载一次,不会重新赋值
实例变量:随着对象的创建而加载。每个对象拥有一份实例变量。
④ 调用者
静态变量:可以被类直接调用,也可以使用对象调用。
Account.setInterestRate(0.0123);
实例变量:只能使用对象进行调用。
Account acct1 = new Account();
System.out.println(acct1.element);
⑤ 判断是否可以调用 —> 从生命周期的角度解释
类变量 | 实例变量 | |
---|---|---|
类 | yes | no |
对象 | yes | yes |
⑥ 消亡时机
静态变量:随着类的卸载而消亡
实例变量:随着对象的消亡而消亡
修饰方法:
(类方法、静态方法)
- 可以通过“类.静态方法”的方式,直接调用静态方法
静态方法内只能调用静态的属性或静态的方法。(
补充:在类的非静态方法中,可以调用当前类中的静态结构(属性、方法)或非静态结构(属性、方法)
类变量 | 实例变量 | |
---|---|---|
类 | yes | no |
对象 | yes | yes |
-
static修饰的方法内,不能使用this和super
-
什么时候需要将属性声明为静态的?
判断当前类的多个实例是否能共享此成员变量,且此成员变量的值是相同的。
开发中,常将一些常量声明是静态的。比如:Math类中的PI
-
什么时候需要将方法声明为静态的?
方法内操作的变量如果都是静态变量(而非实例变量)的话,则此方法建议声
明为静态方法
开发中,常常将工具类中的方法,声明为静态方法。比如:Arrays类、Math类
- 值得思考的题
public class StaticTest { public static void main(String[] args) { Order order = null; order.hello(); System.out.println(order.count); } } class Order { public static int count = 1; public static void hello() { System.out.println("hello!"); } }
由于类中声明为静态,则在程序运行时就已经加载了类中的属性和方法 .
2 final关键字的使用
(固定住 , 这样就不会被随意修改 , 一般用于功能完善的方法和重复使用的固定数字)
-
final的理解:最终的\断子绝孙的
-
可修饰:类、方法、变量
-
具体说明:
3.1 final修饰类:表示此类不能被继承。(extends)
比如:String、StringBuffer、StringBuilder类
但可以被调用
public class Something {
public static void main(String[] args) {
Other o = new Other();
new Something().addOne(o);
}
public void addOne(final Other o) {
o.i++; //可以调用
}
}
class Other {
public int i;
}
3.2 final修饰方法:表示此方法不能被重写
比如:Object类中的getClass()
3.3 final修饰变量:既可以修饰成员变量,也可以修饰局部变量。
此时的"变量"其实就变成了"常量",意味着一旦赋值,就不可更改。
3.3.1 final修饰成员变量的赋值?
显式赋值
final int num; num = 10;
代码块中赋值
final int MAX_SCORE;
>
> {
> MAX_SCORE = 100;
> }
构造器中赋值
final int LEFT; public E(){ LEFT = 2; } public E(int left){ LEFT = left; }
3.3.2 final修饰局部变量:
方法内声明的局部变量:在调用局部变量前,一定需要赋值。而且一旦赋值,就不可更改
public void method(){ final int num; num = 10; // num++; System.out.println(num); }
方法的形参:在调用此方法时,给形参进行赋值。而且一旦赋值,就不可更改
public void method(final int num){ // num++; System.out.println(num); }
-
final与static搭配:修饰成员变量时,此成员变量称为:全局常量。
常用于一个特定的数字要重复调用 , 避免不知道其意义 .
比如:Math的PI
3 单例模式
- 设计模式概述:
设计模式是在大量的实践中总结
和理论化
之后优选的代码结构、编程风格、以及解决问题的思考方式。设计模式免去我们自己再思考和摸索。
经典的设计模式一共有23种。
-
单例模式(Singleton):
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。 -
实现单例模式:
饿汉式
class Bank{ //1. 类的构造器私有化 private Bank(){ } //2. 在类的内部创建当前类的实例 //4. 此属性也必须声明为static的 private static Bank instance = new Bank(); //3. 使用getXxx()方法获取当前类的实例,必须声明为static的 public static Bank getInstance(){ return instance; } }
懒汉式
class GirlFriend{ //1.类的构造器私有化 private GirlFriend(){ } //2. 声明当前类的实例 //4. 此属性也必须声明为static的 private static GirlFriend instance = null; //3. 通过getXxx()获取当前类的实例,如果未创建对象,则在方法内部进行创建 public static GirlFriend getInstance(){ if(instance == null){ instance = new GirlFriend(); } return instance; } }
- 对比两种模式(
特点:
饿汉式:“立即加载”,随着类的加载,当前的唯一实例就自动创建了
懒汉式:“延迟加载”,在需要使用的时候手动创建。
优缺点:
饿汉式:(优点)写法简单,由于内存中较早加载,使用更方便、更快。是线程安全的。
(缺点)内存中占用时间较长。
懒汉式:(优点)在需要的时候进行创建,节省内存空间。
(缺点)线程不安全
- 运用场景
手机app,打开界面时,布满整个屏幕
2
main()方法的剖析
public static void main(String args[]){}
-
理解1:看做是一个普通的静态方法
public class MainTest { public static void main(String[] args) { //程序的入口 String[] arr = new String[]{"AA","BB","CC"}; Main.main(arr); } } class Main{ public static void main(String[] args) { //看做是普通的静态方法 System.out.println("Main的main()的调用"); for (int i = 0; i < args.length; i++) { System.out.println(args[i]); } } }
-
理解2:看做是程序的入口,格式是固定的。
-
与控制台交互(如何从键盘获取数据?)
传值方式
方式1:使用Scanner
方式2:使用main()的形参进行传值。
4 代码块1
回顾:类中可以声明的结构:属性、方法、构造器;代码块(或初始化块)、内部类
-
作用:
用来初始化类或对象的信息(即初始化类或对象的成员变量) -
代码块的修饰:
只能使用static进行修饰。 -
代码块的分类:
**静态代码块:**使用static修饰
**非静态代码块:**没有使用static修饰 -
具体使用:
4.1 静态代码块:- 随着类的加载而执行
- 由于类的加载只会执行一次,进而静态代码块也只会执行一次
- 作用:用来初始化类的信息
- 内部可以声明变量、调用属性或方法、编写输出语句等操作。
- 静态代码块的执行要先于非静态代码块的执行
- 如果声明有多个静态代码块,则按照声明的先后顺序执行
- 静态代码块内部只能调用静态的结构(即静态的属性、方法),非静态不可以
4.2 非静态代码块:
- 随着对象的创建而执行
- 每创建当前类的一个实例,就会执行一次
- 作用:用来初始化对象的信息
- 内部可以声明变量、调用属性或方法、编写输出语句等操作。
- 如果声明有多个非静态代码块,则按照声明的先后顺序执行
- 非静态代码块内部可以调用静态的结构(即静态的属性、方法),静态也可以
public User(){
System.out.println("新用户注册");
registrationTime = System.currentTimeMillis();//获取系统当前时间 (距离1970-1-1 00:00:00的毫秒数)
userName = System.currentTimeMillis() + "";
password = "123456";
}
___________________________________________________
//可改成
{
System.out.println("新用户注册");
registrationTime = System.currentTimeMillis();//获取系统当前时间 (距离1970-1-1 00:00:00的毫秒数)
}
//代码块的使用
public User1(){
userName = System.currentTimeMillis() + "";
password = "123456";
}
5 赋值先后顺序
- 可以给类的非静态的属性(即实例变量)赋值的位置有:
① 默认初始化
② 显式初始化 或 ⑤ 代码块中初始化
③ 构造器中初始化
④ 有了对象以后,通过"对象.属性"或"对象.方法"的方法进行赋值
-
执行的先后顺序:
① - ②/⑤ - ③ - ④ -
给实例变量赋值的位置很多,开发中如何选?
显示赋值:比较适合于每个对象的属性值相同的场景
构造器中赋值:比较适合于每个对象的属性值不相同的场景
-
执行口诀
由父及子 , 静态先行
有几个类就先执行几个类中的静态 , 切记子类的父类要先执行 2
public class Test02 { static int x, y, z; static { int x = 5; x--; //4 XXX错了 在代码块里定义了一个局部变量,在出了代码块的生命周期后 ,这个局部变量就消亡了 . 此x非 Test02.x } static { x--; //3 XXX 从初始值开始-- = -1 } public static void method() { y = z++ + ++z; //-1+1=0 } public static void main(String[] args) { System.out.println("x=" + x); //-1 z--; //-1 method(); System.out.println("result:" + (z + y + ++z)); //1+0+2=3 } }
//代码块先于构造器执行 public class Test03 { public static void main(String[] args) { Sub s = new Sub(); } } class Base{ Base(){ method(100); //2 是子类已经重写的方法 因为默认省略了 this.method 表示的是当前对象的方法 } { System.out.println("base"); //1 一定是先执行代码块 } public void method(int i){ System.out.println("base : " + i); } } class Sub extends Base{ Sub(){ super.method(70); //表示被重写的父类的代码 . } { System.out.println("sub"); } public void method(int j){ System.out.println("sub : " + j); } }