static关键字
- 注
- static 翻译为“静态的”
- 所有static关键字修饰的都是和类相关的,类级别的
- 所有static修饰的,都是采用“ 类名. ”的方式访问
- static修饰的变量:静态变量
- static修饰的方法:静态方法
变量的分类
- 局部变量
- 成员变量
- 实例变量
- 静态变量
package static和this;
public class Test01 {
public static void main(String[] args) {
}
}
class User{
//成员变量中的实例变量
int i;
//实例方法
public void m1(){
//局部变量
int a;
}
//成员变量中的静态变量
static int j;
//静态方法
public static void m2(){
//局部变量
int k;
}
}
什么时候使用静态变量
- 如果这个类型的所有对象中某个属性都是一样的,就可以将其定义为静态变量,因为若定义为实例变量,就相对浪费空间
- 一个对象一份,实例变量
- 所有对象一份,静态变量
注
- 静态变量在类加载的时候初始化,不需要new对象
- 静态变量存储在方法区,一般静态变量有一个固定的值
package static和this;
public class Test02 {
public static void main(String[] args) {
//实例化对象
Chinese chinese = new Chinese("广东","张三");
//访问对象的地址属性
System.out.println(chinese.address);
//访问对象的静态变量
System.out.println(Chinese.country);
}
}
class Chinese{
//一个对象一份,实例变量
String address;
//一个对象一份,实例变量
String name;
//所有对象一份,静态变量
static String country = "中国";
//构造方法
public Chinese(String address, String name) {
this.address = address;
this.name = name;
}
public Chinese() {
}
}
空指针异常和静态的关系
注
- 关于静态属性和实例属性的调用
- 实例数据:一定要使用“引用."来访问
- 静态数据:建议使用”类名.“来访问,”引用.“是可以的,但是不建议。因为会让读者产生困惑,默认为其为实例数据
- 什么时候会出现空指针异常
- ”空引用“访问“实例”相关的数据的时候,会出现
- 因为静态数据是和实例没有关系的,所以空引用访问静态数据的时候,不会出现空指针异常
package static和this;
public class Test03 {
public static void main(String[] args) {
//构建对象
Student student = new Student(1,"张三");
//访问id属性
System.out.println(student.id);
//调用实例方法
student.doOther();
//正确调用静态方法 ———— 使用“类名.”的方式调用
Student.doSome();
//空引用
student = null;
//空指针异常
// System.out.println(student.id); //java.lang.NullPointerException
//空引用访问静态变量
System.out.println(student.country); //中国
//空引用访问静态方法
student.doSome(); //doSome...
//由此可见,空引用访问静态数据的时候,不会出现空指针异常(但是不建议使用“引用.”的方式调用静态数据)
}
}
class Student{
int id;
String name;
static String country = "中国";
public Student() {
}
public Student(int id, String name) {
this.id = id;
this.name = name;
}
//静态方法
public static void doSome(){
System.out.println("doSome...");
}
//实例方法
public void doOther(){
System.out.println("doOther...");
}
}
- 实例方法就是对象的一个行为
- 静态方法就是类的一个行为
静态代码块
- 使用static关键字可以定义:静态代码块
- 定义:在类加载的时候,并在main方法之前执行的代码块
- 语法:
static{
//Java语句
}
- 执行顺序:自上而下,且一个类中可以写多个
- 作用:
- 提供了一个特殊的时机(类加载时机)
- 在业务中,某个类加载了,就记录一下类加载的信息
- 实例
package static和this;
public class Test04 {
//静态代码块
static {
System.out.println("静态代码块01执行了...");
}
static {
System.out.println("静态代码块02执行了...");
}
//程序执行入口
public static void main(String[] args) {
System.out.println("主方法main执行了...");
}
static {
System.out.println("静态代码块03执行了...");
}
}
/*
静态代码块01执行了...
静态代码块02执行了...
静态代码块03执行了...
主方法main执行了...
注:不管静态代码块是在主方法的上面还是下面,都是静态代码块先执行,再执行主方法
* */
代码执行顺序
- 静态方法在什么时候初始化? —— 类加载时初始化
- 静态变量存储在哪里? —— 方法区
- 静态代码块在什么时候执行? —— 类加载时执行
- 实例
package static和this;
public class Test05 {
//静态变量
static int i = 100;
//静态代码块
static {
System.out.println(i);
}
//实例变量
int j = 100;
static {
// System.out.println(j); //无法从静态上下文中引用非静态 变量 j
//静态代码块在类加载的时候执行,且只执行一次;实例变量在构造方法执行的时候内存空间才开辟,所以不能访问
}
static {
// System.out.println(name); //非法前向引用
//静态代码块也遵循自上而下的执行顺序
}
static String name = "BBC";
static String address = "中国";
static {
System.out.println(address);
}
//所以在主方法main执行之前就可能已经执行了很多代码了
public static void main(String[] args) {
System.out.println("i = " + i);
}
}
- 静态代码块之间有执行的先后顺序
- 静态代码块和静态变量也有先后顺序
实例代码块
- 定义:在构造方法执行之前,自动执行的代码块
- 语法:
{
//java语句;
}
- 作用:一个时机(对象构造时机)
- 实例
package static和this;
public class Test06 {
public static void main(String[] args) {
Users users = new Users();
Users users1 = new Users("张三","01");
Users users2 = new Users("李四","02");
}
}
class Users{
//实例语句块
static int i = 0;
//为什么要用静态变量,而不是实例变量?
//因为若是实例变量的话,每次new一个对象,就会新建一个i变量,使i的值不会改变
{
System.out.println("实例语句块执行了...");
i++;
System.out.println("构建了第" + i + "个Users对象");
}
String name;
String id;
public Users() {
System.out.println("无参构造方法执行了...");
System.out.println();
}
public Users(String name, String id) {
this.name = name;
this.id = id;
System.out.println("有参构造方法执行了...");
System.out.println();
}
}
代码执行顺序
package static和this;
public class Test07 {
static {
System.out.println("静态代码块执行了...");
}
public static void main(String[] args) {
System.out.println("主方法 begin");
new Test07().doSome();
System.out.println("主方法 over");
}
{
System.out.println("实例代码块执行了...");
}
static {
System.out.println("静态代码块02执行了...");
}
public void doSome(){
System.out.println("doSome...");
}
}
this关键字
- 定义:this保存当前对象的内存地址,指向自身,所以this代表的就是“当前对象”
- this存储在堆内存中对象内部
- 注: this可以使用在实例方法中,不能使用在静态变量中
- 实例
package static和this;
public class Test08 {
public static void main(String[] args) {
Costomer costomer = new Costomer("张三","01");
costomer.doSome("李四"); //李四doSome...
//没有this的时候,name就是传入的实参
costomer.doOther("李四"); //张三doOther...
//this指向当前对象,所以name是调用方法的对象张三
}
}
class Costomer{
String name;
String id;
public Costomer() {
}
public Costomer(String name, String id) {
this.name = name;
this.id = id;
}
public void doSome(String name){
System.out.println(name + "doSome...");
}
public void doOther(String name){
System.out.println(this.name + "doOther...");
}
}
this什么时候不能省略
- 为了区分局部变量和实例变量的时候
package static和this;
public class Test09 {
public static void main(String[] args) {
Students students = new Students("张三");
students.setName("李四");
//李四就是局部变量,对应下面的setName()方法中,将局部变量的李四赋值给了实例变量的name
System.out.println(students.getName());
}
}
class Students{
private String name;
public Students() {
}
public Students(String name) {
this.name = name;
}
public String getName() {
return this.name;
//这里的this就可以省略,因为没有区分局部变量和实例变量
}
public void setName(String name) {
this.name = name;
//这里就不能省略,因为有局部变量,为了区分局部变量和实例变量,就需要加上this表示实例变量
}
// public void setName(String i){
// name = i;
// //上面的setName方法也可以改成这样,但是因为引入了莫名其妙的参数,使读者理解代码的难度增加,所以一般都是使用上面一种
// }
}
this的用法
- this除了可以使用在实例方法中,还可以使用在构造方法中,通过当前的构造方法去调用另一个本类的构造方法,可以做到代码复用
注: 对this()的调用必须是构造器中的第一个语句(构造器就是构造方法)
语法:
this(实际参数列表);
例子:
package static和this;
public class Test010 {
public static void main(String[] args) {
//无参构造
Data data = new Data();
//有参构造
Data data1 = new Data(2000,1,22);
data.print(); //1999-8-22
data1.print(); //2000-1-22
}
}
class Data{
private int year;
private int month;
private int day;
public Data() {
//在构造方法中使用this,去调用另外一个构造方法,注意:一定要在同一个类中
this(1999,8,22);
//相当于以下代码
// this.year = 1999;
// this.month = 8;
// this.day = 22;
}
public Data(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
//打印日期
public void print(){
System.out.println(year + "-" + month + "-" + day);
}
}