文章目录
static成员
1. 谈学生类
每个对象都有自己特有的名字、性别,年龄,等成员信息,这些信息就是对不同学生来进行描述的,如下所示:
class Student {
private String name = "wuswei";
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void doClass() {
System.out.println("上课!");
}
}
public class Test {
public static void main(String[] args) {
Student s1 = new Student("Li leilei", 10);
Student s2 = new Student("Han MeiMei", 19);
Student s3 = new Student("Jim", 18);
}
}
假设三个同学是同一个班的,那么他们上课肯定是在同一个教室,那既然在同一个教室,那能否给类中再加一个成员变量,来保存同学上课时的教室呢?答案是不行的。
在Student类中定义的成员变量,每个对象中都会包含一份(称之为实例变量),因为需要使用这些信息来描述具体的学生。而现在要表示学生上课的教室,这个教室的属性并不需要每个学生对象中都存储一份,而是需要让所有的学生来共享。在Java中,被static修饰的成员,称之为静态成员,也可以称为类成员,其不属于某个具体的对象,是所有对象所共享的。
2. static修饰成员变量
static修饰的成员变量,称为静态成员变量,静态成员变量最大的特性:不属于某个具体的对象,是所有对象所共享的。
【静态成员变量特性】
- 不属于某个具体的对象,是类的属性,所有对象共享的,不存储在某个对象的空间中
- 既可以通过对象访问,也可以通过类名访问,但一般更推荐使用类名访问
- 类变量存储在方法区当中
- 生命周期伴随类的一生(即:随类的加载而创建,随类的卸载而销毁)
成员变量
- 静态成员变量/类变量/类成员
- 非静态成员变量/普通成员变量
我们可以将之前的代码进行改造加入他们共同的班级
可以才class Student里面加入
public static String classRoom = “107java直播间”;
进行改造
class Student {
private String name = "wuswei";
private int age;
public static String classRoom = "107java直播间";
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Test {
public static void main(String[] args) {
Student s1 = new Student("Li leilei", 10);
Student s2 = new Student("Han MeiMei", 19);
Student s3 = new Student("Jim", 18);
}
在调试的时候不显示classRoom,那么classRoom就在方法区放的只有使用的时候才会出现。
public class Test {
public static void main(String[] args) {
Student s1 = new Student("Li leilei", 10);
Student s2 = new Student("Han MeiMei", 19);
Student s3 = new Student("Jim", 18);
System.out.println(s1.classRoom);
System.out.println(s2.classRoom);
System.out.println(s3.classRoom);
System.out.println(Student.classRoom);
}
}
结果:
这里我们可以通过new的对象来访问classRoom的内容也可以通过类名来访问。
静态的不依赖于对象
静态的成员变量 不属于对象 所以 不用通过对象的引用来访问,直接通过类名就可以访问的。
3. static修饰成员方法
一般类中的数据成员都设置为private,而成员方法设置为public,那设置之后,Student类中classRoom属性如何在类外访问呢?
成员方法
- 静态成员方法/类方法
- 非静态成员方法
class Student{
private String name;
private int age;
private static String classRoom = "107java直播间";
}
public class TestStudent {
public static void main(String[] args) {
System.out.println(Student.classRoom);
}
}
编译失败:
Error:(10, 35) java: classRoom 在 extend01.Student 中是 private 访问控制
那此时被private修饰static属性应该如何访问呢?
Java中,被static修饰的成员方法称为静态成员方法,是类的方法,不是某个对象所特有的。静态成员一般是通过静态方法来访问的。
class Student{
private String name;
private int age;
private static String classRoom = "107java直播间";
public static String getClassRoom(){
return classRoom;
}
}
public class TestStudent {
public static void main(String[] args) {
System.out.println(Student.getClassRoom());
}
}
结果:
【静态方法特性】
- 不属于某个具体的对象,是类方法
- 可以通过对象调用,也可以通过类名.静态方法名(…)方式调用,更推荐使用后者
- 不能在静态方法中访问任何非静态成员变量
public static String getClassRoom(){
System.out.println(this);//this不可以在这里使用
return classRoom;
}
// 编译失败:Error:(35, 28) java: 无法从静态上下文中引用非静态 变量 this
public static String getClassRoom(){
age += 1;//age在上面属于非静态
return classRoom;
}
// 编译失败:Error:(35, 9) java: 无法从静态上下文中引用非静态 变量 age
- 静态方法中不能调用任何非静态方法,因为非静态方法有this参数,在静态方法中调用时候无法传递this引用
public static String getClassRoom(){
doClass();
return classRoom;
}
// 编译报错:Error:(35, 9) java: 无法从静态上下文中引用非静态 方法 doClass()
总结:
- 普通成员方法内部是可以使用静态成员方法的
- 在静态成员方法内部是不可以调用非静态成员方法的
- 在静态成员方法内部是不可以调用非静态的数据成员
- 只要是非静态的数据成员,都需要通过对象的引用才可以调用
- 静态方法里面不是你使用this
建议:
获取静态的成员变量还在是设置静态的成员变量,此时的方法最好是静态的,否则你要是非静态的,必须实例化对象
4. static成员变量初始化
静态成员变量的初始化:
- 就地初始化:在定义时直接给出初始值
private static String classRoom = "107java直播间";
- 默认初始化
- 可以通过提供get和set方法初始化
public static void setClassRoom(String classRoom) {
Student.classRoom = classRoom;
}
public static String getClassRoom() {
return classRoom;
}
- 静态代码块初始化 (往后看)
代码块
代码块概念以及分类
使用{} 定义的一段代码称为代码块。根据代码块定义的位置以及关键字,又可分为以下四种:
- 普通代码块
- 构造块(非静态代码块/实例代码块)
- 静态块
- 同步代码块(后续讲解多线程部分再谈)
1. 普通代码块
普通代码块:定义在方法中的代码块.
public class Main{
public static void main(String[] args) {
{ //直接使用{}定义,普通方法块
int x = 10 ;
System.out.println("x1 = " +x);
}
int x = 100 ;
System.out.println("x2 = " +x);
}
}
// 执行结果
x1 = 10
x2 = 100
2. 构造代码块
构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。
class Student {
public String name= "wuswei";
private int age;
public static String classRoom = "107java直播间";
private static int size = 10;
public Student(String name, int age,int si) {
this.name = name;
this.age = age;
size = si;
System.out.println("带有三个参数的构造方法!");
}
{
name="caocao";//不改变
System.out.println("非静态代码块/实例代码块/构造代码块!->初始化非静态的数据成员");
}
public Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("带有二个参数的构造方法!");
}
}
public class Test4 {
public static void main(String[] args) {
Student student = new Student("张三",10,10);
System.out.println(student.name);
Student student1 = new Student("李四",20);
}
}
结果:
流程
由此代码可以知:在调用构造方法前,先执行构造代码块(实例代码块/非静态代码块)然后是构造方法
可以简单的认为,编译器写好代码之后,会把非静态代码拷贝到构造方法的最前面
在传值的时候,如果都是非静态的,那么就看定义的顺序。谁在后,谁就是哪个值
3. 静态代码块
使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。
class Student {
public String name= "wuswei";
private int age;
public static String classRoom = "107java直播间";
private static int size = 10;
public Student(String name, int age,int si) {
this.name = name;
this.age = age;
size = si;
System.out.println("带有三个参数的构造方法!");
}
static {
System.out.println("静态代码块->初始化金泰的数据成员/提前准备一些数据");
}
{
name = "caocao";//不改变
System.out.println("非静态代码块/实例代码块/构造代码块!->初始化非静态的数据成员");
}
}
public class Test4 {
public static void main(String[] args) {
Student student = new Student("张三",10,10);
}
}
结果:
当同时存在静态代码块和非静态代码块和构造方法的时候他的顺序是静态代码块——>非静态代码块——>构造方法
接上面的类引例
public class Test4 {
public static void main(String[] args) {
Student student = new Student("张三",10,10);
System.out.println("===========================");
Student student1 = new Student("李四",20,20);
}
}
结果:
根据这个代码可以得到,静态代码块不管生成多少个对象,其只会执行一次
注意事项
静态代码块不管生成多少个对象,其只会执行一次
静态成员变量是类的属性,因此是在JVM加载类时开辟空间并初始化的
如果一个类中包含多个静态代码块,在编译代码时,编译器会按照定义的先后次序依次执行(合并)
实例代码块只有在创建对象时才会执行
对象的打印
public class Person {
String name;
String gender;
int age;
public Person(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public static void main(String[] args) {
Person person = new Person("Jim","男", 18);
System.out.println(person);
}
}
// 打印结果:day20210829.Person@1b6d3586
系统自带的toString
如果想要默认打印对象中的属性该如何处理呢?答案:重写toString方法即可。
public class Person {
String name;
String gender;
int age;
public Person(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
'}';
}
public static void main(String[] args) {
Person person = new Person("Jim","男", 18);
System.out.println(person);
}
}
// 输出结果:Person{name='Jim', gender='男', age=18}
对于你想输出一个对象的引用值得时候,如果你没有自己写一个toString方法的化,那么,就会调用Object这个类的方法。
一句话: 如果自己写了调用自己的,如果没写调用Object这个类的方法。
在idea中toString的快捷方式
以上内容如果对诸位有帮助的话可以留下你们的赞赞,如果我书写的有问题,请在评论区指出,我会及时修改的。