1.static 静态变量
package com.itheima.a01staticdemo01;
public class Student {
private String name;
private int age;
public static String teacherName;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
public void study() {
System.out.println(name+"在学习");
}
public void show(){
System.out.println(name+","+age+" ,"+teacherName);
}
}
package com.itheima.a01staticdemo01;
public class StudentTest {
public static void main(String[] args) {
//static修饰的techername共享
//类名调用变量
Student .teacherName="小陈老师";
Student s1 = new Student("张三",18);
s1.study();
s1.show();
Student s2 = new Student("李四",26);
s2.study();
s2.show();
}
}
静态变量是随着类的加载而加载的,优先于对象的
对象s1提供地址值访问静态区的变量,如图 s1访问静态区,就是通过地址0X0011这个地址线找到了静态区的变量teachername
2.静态方法和工具类
package com.itheima.a01staticdemo02;
public class ArrutilTest {
public static void main(String[] args) {
//测试工具类的二个方法是否正确
int[]arr={1,2,3,4,5};
String str = Arrutil.pirintArr(arr);
System.out.println(str);
double[]arr1={1.1,2.2,3.3,4.4,5.5};
double avg = Arrutil.getAverage(arr1);
System.out.println(avg);
}
}
package com.itheima.a01staticdemo02;
public class Arrutil {
//私有化构造方法
//目的:为了不让外界创建他的对象
private Arrutil(){
}
//需要定义为静态的,方便调用
public static String pirintArr(int []arr){
StringBuffer sb=new StringBuffer();
sb.append("[");
for(int i=0;i<arr.length;i++){
if(i==arr.length-1){
sb.append(arr[i]);
}else{
sb.append(arr[i]+",");
}
}
sb.append("]");
return sb.toString();
}
public static double getAverage(double[] arr){
double avg=0;
for(int i=0;i<arr.length;i++){
avg+=arr[i];
}
return avg/=arr.length;
}
}
package com.itheima.a01staticdemo03;
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
//1.创建一个集合用来存储学生对象
ArrayList<Student> list = new ArrayList<>();
//2.创建3个学生对象
Student s1=new Student("zhangsan",18,"男");
Student s2=new Student("lisi",19,"男");
Student s3=new Student("wangwu",20,"女");
//将三个学生对象添加在集合里
list.add(s1);
list.add(s2);
list.add(s3);
//4.调用工具类的方法
int ageMax = Studentutil.getAgeMax(list);
System.out.println(ageMax);
}
}
package com.itheima.a01staticdemo03;
import java.util.ArrayList;
import java.util.List;
public class Studentutil {
private Studentutil() {
}
public static int getAgeMax(ArrayList<Student> list) {
int max=list.get(0).getAge();
for (int i = 1; i < list.size(); i++) {
//list.get(i)集合里的每一个元素 ,每个元素是一个学生对象,我们还需getAge获取到年龄之后再进行比较
int tmpAge = list.get(i).getAge();
if (tmpAge > max) {
max = tmpAge;
}
}
return max;
}
}
package com.itheima.a01staticdemo03;
public class Student {
private String name;
private int age;
private String gender;
public Student() {
}
public Student(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
/**
* 获取
* @return name
*/
public String getName() {
return name;
}
/**
* 设置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取
* @return age
*/
public int getAge() {
return age;
}
/**
* 设置
* @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取
* @return gender
*/
public String getGender() {
return gender;
}
/**
* 设置
* @param gender
*/
public void setGender(String gender) {
this.gender = gender;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + ", gender = " + gender + "}";
}
}
3.总结
this表示当前地方调用的地址值
比如图里的s1和s2就是方法调用者, 所以说s1的地址和this的地址一样
我们平常写javabean类的时候是因为变量的名字一样没有加this关键字,严格的讲应该加this
比如说这里 this.show2() ,执行s1.show1()的时候 我们是调用者s1调用了show1的方法,然后show1的方法里面s1调用了show2()方法
静态区没有this关键字
静态区的方法不能调用成员的变量 也就是实例变量
因为静态区没有this关键字 调用show方法的时候没有对象调用方法
非静态区的变量通过对象能找到静态区的变量 teachername
一、static关键字是什么?
static是静态的意思,是一个修饰符,就像是一个形容词,是用来形容类,变量,方法的。在声明static关键字时,可以在前面加上static修饰,用static修饰的成员变量称做类变量(static变量、静态变量)
二、加了static关键字有什么用?
被static关键字修饰的方法或者变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名去进行访问
static还有一个很关键的作用就是可以通过static来构建一个静态代码块,在这个静态代码块中,你可以将一些变量初始化,在程序加载的时候static代码块是优先加载的,因此可以说成是用来形成静态代码块以优化程序性能.
三、static静态变量和实例变量
说了一些static关键字的基本理念和它的作用,空谈不行,要将其应用到实例化代码中,接下来讲讲静态变量和实例变量的声明
1、两种变量的声明
- 比方说我们下面定义一个System类🎄
class System{
int name; //姓名
int num; //编号
static int onlineNumber; //在线人数
}
- 可以看出,这里的姓名和编号都是属于普通的实例成员变量,但是对于在线人数onlineNumber,前面却加了static关键字,表明其是一个静态变量
注意:只要成员变量可以用static关键字修饰,普通的局部变量不可以,是非法的
实例变量就是非静态区的成员变量
2、两种变量的区别
对于实例变量,改变其中一个对象的实例变量不会影响其他对象的实例变量,因为它们在堆内存中是一块块独立的区域,各自有各自的内存,是互不相干的;但是你通过任何对象去修改一个static修饰的成员变量,都可以将其修改,改变其中一个对象的类变量会影响其他对象的这个类变量,通俗一点来讲就是对象共享类变量
在Java中,当程序执行的时候,类的【字节码文件】会被加载到内存中,如果类没有创建对象,则类的成员变量不会被分配内存,但对于类变量,也就是静态变量,它有在堆中有一个专属的静态变量区,,当JVM虚拟机将字节码加载到内存时,就会为这个onlineNumber在线人数在堆区中分配出一段空间用于放置💡
当你去通过类定义对象的时候,这个时候才会在堆内存中为不同的对象分配不同的内存空间,上面我们说过,所有对象的类变量都是相同的一块内存空间,光这么说太抽象了,我们来看个
【堆栈内存原理分布图】
- 然后在配合一个示例,大家可以先对照着我前面讲的把这个逻辑理一遍🔍
public class User {
//static修饰的成员变量,内存中只有一份,可以被共享
public static int onlineNumber = 16;
//静态成员变量,直接用类名访问
//实例成员变量 - 用对象访问
private String name;
private int age;
public static void main(String[] args) {
//直接用类名访问,不用对象
//1.类名.静态成员变量
System.out.println(User.onlineNumber);
//2.对象名.实例成员变量
User u = new User();
//System.out.println(User.name); 不能用类名去访问实例成员变量
u.name = "张三";
u.age = 21;
System.out.println(u.name);
System.out.println(u.age);
System.out.println("-----------");
u.onlineNumber++; //新来了一个人
User u2 = new User();
u2.name = "李四";
u2.age = 22;
System.out.println(u2.name);
System.out.println(u2.age);
System.out.println("-----------");
u2.onlineNumber++; //体现了共享的特点
System.out.println(u.onlineNumber);
System.out.println(User.onlineNumber);
System.out.println(onlineNumber);
//同一个类中静态成员变量的访问可以省略类型
}
}
这个是运行结果
每个对象都指向堆区中的一块内存地址,每一块内存地址都是独立的,互不干扰,但是后面可以看出,两块不同的堆区内存均指向同一块静态变量区的地址,这就很好地印证了我上面说的那一点,所有对象的类变量都是相同的一块内存空间,也就是对象调用静态变量都能用.
因为对象调用的时候是在静态区调用的
- 从运行结果可以看出,通过下面两条语句,看运行结果,都可以实现在线人数的递增,这就印证了对象共享类变量这句话📖
u.onlineNumber++;
u2.onlineNumber++;
- 有一点要注意的是这句代码是不可行的,上面讲到过,当还没有通过类去构建对象的时候,是不会在堆内存中为其分配空间的,也就是说,这个时候堆内存中完全没有name这个变量,那你去直接用类名访问的话,是在访问哪个对象的姓名呢?
- 有一点要注意的是这句代码是不可行的,上面讲到过,当还没有通过类去构建对象的时候,是不会在堆内存中为其分配空间的,也就是说,这个时候堆内存中完全没有name这个变量,那你去直接用类名访问的话,是在访问哪个对象的姓名呢?
//System.out.println(User.name); 不能用类名去访问实例成员变量
- 好,我们讲本小块的最后一个知识点,就是如何去访问这个静态成员变量,一共是有下述三种方法,这三种方法就对应最后的这三句代码
①类名.静态成员变量(推荐)
②对象名.静态成员变量(不推荐)
③同一个类中,访问静态成员可以省略类名不写 -
System.out.println(u.onlineNumber); System.out.println(User.onlineNumber); System.out.println(onlineNumber); //同一个类中静态成员变量的访问可以省略类型
四、static静态方法和实例方法
1、两种方法的声明
//静态方法 - 实现通用功能
public static int getMax(int x,int y){
return x > y ? x : y;
}
//实例方法 - 直接访问对象的实例成员
public void speak(){
name = "张三";
System.out.println(name + "在说话");
}
- 通过以上代码,相信大家对静态方法和实例方法有了一个基本的认识,在声明方法时候
- 如果你想要实现一个通用功能,那就用静态方法;
- 但如果你想要直接访问对象的实例成员,则用实例方法
注意: static关键字需要放在方法的类型之前,而不可以乱放置;而且不可以用static修饰构造方法
2、两种方法的区别
- 上面在说到类加载时的字节码文件会被加载到内存中,而方法中存在一个入口地址,类的实例方法不会被分配入口地址,只有当该类创建了对象后,类中的实例方法才会被分配入口地址。而且当你创建了一个对象之后再继续创建对象时,不会再为实例方法分配入口地址,通俗地说就是,方法的入口地址所有对象共享
- 在实例方法中你不仅可以操作实例变量,而且可以操作类变量,也就是static变量
- 对于实例方法,它还可以调用类中其他的实例方法和类方法(不包括构造方法)
public static void main(String[] args) {
//1.类名.静态成员方法
System.out.println(Student.GetMax(10, 30));
System.out.println(GetMax(50, 99)); //可不用类名
//study(); 需要对象名去访问
//2.对象名.实例方法
Student st = new Student();
st.name = "孙悟空";
st.study();
//3.对象名.静态成员方法(语法可行,但是不推荐)
System.out.println(st.GetMax(1,9));
}
- 从上述代码我们可以看出静态成员方法和实例成员方法的调用格式,对于静态成员方法,它的格式有两种,我们也是推荐第一种,因为系统也是支持第一种调用方法,
- ①类名.静态成员方法
②对象名.静态成员方法(语法可行,但是不推荐)
对于这个,大家可以记住一句话
对于静态的东西,直接用类名调用即可,不会出错
- 而对于这个实例成员方法,则只能用对象名去调用,因为其是属于对象的一部分,和实例成员变量一样,不可以用类名去调用,更不能直接调用,因为具体的对象其所对应的具体方法,内部的成员变量 也是相互对应的
五、static关键字注意事项
1、静态方法只能访问静态的成员,不可以’直接’访问实例成员
2、实例方法可以访问静态的成员,也可以访问实例成员
3、静态方法中是不可以出现this关键字的
- 最后一点,就是对于静态方法中不可以出现this关键字,因为this代表的是当前对象,静态方法中是可以不用声明实例对象的,但是this可以出现在实例方法中,就如上一个注意事项中的最后一句代码,this代表正好是这个对象所对应的地址,就可以访问其所对应的成员变量