static关键字
介绍
static表示静态,是java中的一个修饰符,可以修饰成员方法,成员变量。
其中,被static修饰的成员变量,叫做静态变量;被static修饰的成员方法,叫做静态方法。
静态变量
调用方式:类名调用(推荐)、对象调用
特点:
● 被该类所有对象共享
● 不属于对象,属于类
● 随着类的加载而加载,优先于对象存在
//所有对象的teacherName将会被赋值为“阿伟”Student.teacherName = "阿伟";Student s1 = new Student();s1.setName("小李");s1.setAge(18);System.out.println(s1.toString());//Student{name = 小李, age = 18, teacherName = 阿伟}Student s2 = new Student();System.out.println(s2.toString());//Student{name = null, age = 0, teacherName = 阿伟}
内存图
注意:
静态区里边的变量是对象共享的,在内存当中只有一份,“谁要用谁去拿”;而非静态的变量是每一个对象独有的。
静态方法
调用方式:类名调用(推荐)、对象调用
特点:
● 多用在测试类和工具类中
● Javabean类中很少会用
拓展:工具类、测试类、Javabean类的区别
● Javabean类:用来描述一类事物的类。比如,Student,Teacher,Dog等
● 测试类:用来检查其他类是否书写正确,带有main方法的类,是程序的入口
● 工具类:不是用来描述一类事物的,而是帮我们做一些事情的类
书写工具类,需注意:
● 类名见名只意(如StudentUtil)
● 私有化构造方法(不让外界创建它的对象)
● 方法定义为静态(方便调用)
练习
定义一个工具类求学生年龄最大值
工具类:
public class StudentUtil {//私有化构造方法private StudentUtil(){}public static int getMaxAge(List<Student> list){if(list.size() == 0)return -1;int max = list.get(0).getAge();for(int i = 1;i < list.size(); i++){int maxTemp = list.get(i).getAge();if(maxTemp > max){max = maxTemp;}}return max;}
}
测试类:
public static void main(String[] args) {List<Student> list = new ArrayList<>();Student stu1 = new Student("张三",15,"男");Student stu2 = new Student("李四",16,"男");Student stu3 = new Student("王五",13,"女");list.add(stu1);list.add(stu2);list.add(stu3);//用工具类当中的方法获取集合中最大学生的年龄int maxAge = StudentUtil.getMaxAge(list);System.out.println(maxAge);//16}
static的注意事项
● 静态方法只能访问静态变量和静态方法(静态方法只能访问静态)
● 非静态方法可以访问静态变量或静态方法,也可以访问非静态的成员变量和非静态的成员方法(非静态可以访问所以)
● 静态方法中是没有this关键字
public class Student {String name;int age;static String teacherName;public void show1(){System.out.println(name + ", " + age + ", " + teacherName);//非静态方法调用静态方法和非静态方法(this可省略不写)//this:表示当前方法调用者的地址值//这个this:是由虚拟机赋值的this.method();this.show2();}public void show2(){System.out.println("成功调用此方法");}public static void method(){System.out.println("静态方法");//不能用this调用静态方法(只能直接调用),也不能调用非静态方法method1();}public static void method1(){//只能输出静态成员变量,非静态不行System.out.println(teacherName);}
}
继承
继承的概述
java中提供了一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起继承关系
public class Student extends person{}
其中,Student称为子类(派生类),Person称为父类(基类或超类)
使用继承的好处
● 可以把多个子类中重复的代码抽取到父类中了,提高代码的复用性。
● 子类可以在父类的基础上,增加其他的功能,使子类更加强大。
什么时候用继承?
当类与类之间,存在相同(共性)的内容,并满足子类是父类的一种,就可以考虑使用继承,来优化代码
继承的特点
● Java只支持单继承,不支持多继承(一个儿子只能有一个父亲,不能有多个)、但支持多层继承
多层继承:子类A继承父类B,父类B可以继承父类C(B是A的直接父类,C是A的间接父类)
● Java中所有的类都直接或者间接继承于Object类。
练习
所作图:
代码如下:
六个Javabean类:
public class Animal {public void eat(){System.out.println("吃饭");}public void drink(){System.out.println("喝水");}
}
public class Cat extends Animal{public void catchMouse(){System.out.println("猫抓老鼠");}
}
public class Dog extends Animal{public void lookHome(){System.out.println("狗在看家");}
}
public class Ragdoll extends Cat{
}
public class LiHua extends Cat{
}
public class Husky extends Dog{public void breakHome(){System.out.println("哈士奇正在拆家!!");}
}
public class Teddy extends Dog{public void touch(){System.out.println("泰迪正在蹭我的腿~");}
}
测试类:
public class Text {public static void main(String[] args) {//1.创建布偶猫对象Ragdoll r = new Ragdoll();r.eat();//吃饭r.drink();//喝水r.catchMouse();//猫抓老鼠//2.创建哈士奇对象Husky h = new Husky();h.eat();//吃饭h.drink();//喝水h.lookHome();//狗在看家h.breakHome();//哈士奇正在拆家!!}
}
继承的注意事项
子类到底能继承父类中的哪些内容
即构造方法不能被继承,成员变量都能被继承,成员方法只继承虚方法表中的方法
对于成员变量:
● 私有的确实可以继承,但得用set/get方法进行赋值和访问
● 静态成员变量可以直接赋值和访问
public class Fu {public String name;public static int age;//静态成员变量private String gender;//私有变量public void setGender(String gender){this.gender = gender;}public String getGender(){return this.gender;}
}public class Zi extends Fu{public int score;
}
测试类:
public class Text {public static void main(String[] args) {Zi z = new Zi();z.name = "张三";z.score = 100;z.age = 15;//age为父类静态成员变量z.setGender("男");System.out.println(z.name + ", " + z.score + ", " + z.age + ", " + z.getGender());//张三, 100, 15, 男}
}
对于成员方法:
从最顶级的父类开始设立了一个虚方法表,一代一代传给自己的子类,大大提高程序的性能
如果子类对象调用的方法不在虚方法表中,则会在上代中一代一代去找
内存图演示:
继承中成员变量、方法和构造方法的访问特点
对于成员变量:
● 就近原则:谁离我近,我就用谁(先在局部位置找,本类成员位置找,父类成员位置找,逐级往上)
● 出现重名需要用this、super关键字来指定访问
public class Fu {String name = "Fu";
}
public class Zi extends Fu{String name = "Zi";public void ziShow(){String name = "ziShow";System.out.println(name);//ziShowSystem.out.println(this.name);//ZiSystem.out.println(super.name);//Fu}
}
public class Text {public static void main(String[] args) {Zi zi = new Zi();zi.ziShow();/*
ziShow
Zi
Fu*/}
}
对于成员方法:
● 直接调用满足就近原则:谁离我近,我就用谁
● super调用,直接访问父类
public class Fu {public void eat(){System.out.println("吃米饭");}public void drink(){System.out.println("喝水");}
}
public class Zi extends Fu{public void lunch(){//先在本类中查看eat和drink方法,就会调用子类的,如果没有,就会调用父类中继承下来的eat和drink方法eat();drink();//直接调用父类的eat和drink方法super.eat();super.drink();}@Overridepublic void eat(){System.out.println("吃意大利面");}@Overridepublic void drink(){System.out.println("喝奶茶");}
}
public class Text {public static void main(String[] args) {Zi zi = new Zi();zi.lunch();/*
吃意大利面
喝奶茶
吃米饭
喝水*/}
}
补充说明:方法的重写
当父类的方法不能满足子类现在的需求时,需要进行方法重写
书写格式
在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法
@Override重写注解
其是放在重写后的方法上,校验子类重写时语法是否正确
方法重写的本质
即子类覆盖了从父类中继承下来的虚方法表里面的方法
方法重写注意事项和要求
● 重写方法的名称、形参列表必须与父类中的一致
● 子类重写父类方法时,访问权限子类必须大于等于父类(空着不写<protected<public)
● 子类重写父类方法时,返回值类型子类必须小于等于父类
● 只有被添加到虚方法表中的方法才能被重写
● 重写方法尽量和父类保持一致
练习
所作图:
代码如下:
public class Dog {public void eat(){System.out.println("狗在吃狗粮");}public void drink(){System.out.println("狗在喝水");}public void lookHome(){System.out.println("狗在看家");}
}public class Husky extends Dog{public void breakHome(){System.out.println("狗在拆家");}
}public class SharPei extends Dog{@Overridepublic void eat(){super.eat();System.out.println("吃骨头");}
}public class ChineseDog extends Dog{@Overridepublic void eat(){System.out.println("狗在吃剩饭");}
}
public class Text {public static void main(String[] args) {Husky h = new Husky();h.eat();h.drink();h.lookHome();h.breakHome();ChineseDog cd = new ChineseDog();cd.eat();cd.drink();cd.lookHome();}/** 狗在吃狗粮
狗在喝水
狗在看家
狗在拆家
狗在吃剩饭
狗在喝水
狗在看家*/
}
总结
对于构造方法:
● 子类构造方法的第一行,有一个默认的super();
● 默认先访问父类中无参的构造方法,再执行自己。
● 子类不能继承父类的构造方法,但是可以通过super调用
● 如果想要方法文父类有参构造,必须手动书写。
this、super使用总结
● this:理解为一个变量,表示当前方法调用者的地址值;
● super:代表父类存储空间。
测试
带有继承结构的标准Javabean类
答案:
父类:
public class Employee {private String id;private String name;private double salary;//ptg生成javabeanpublic Employee() {}public Employee(String id, String name, double salary) {this.id = id;this.name = name;this.salary = salary;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}public String toString() {return "Employee{id = " + id + ", name = " + name + ", salary = " + salary + "}";}public void work(){System.out.println("正在工作");}public void eat(){System.out.println("吃米饭");}
}
两个子类:
public class Manage extends Employee{private double bouns;//alt+insert重造构造器public Manage() {}public Manage(String id, String name, double salary, double bouns) {//调用了父类的有参构造器super(id, name, salary);this.bouns = bouns;}//ptgpublic double getBouns() {return bouns;}public void setBouns(double bouns) {this.bouns = bouns;}public String toString() {return "Manage{bouns = " + bouns + "}";}//方法的重写@Overridepublic void work() {System.out.println("经理正在管理其他人");}
}public class Cooker extends Employee{//alt+insertpublic Cooker() {}public Cooker(String id, String name, double salary) {super(id, name, salary);}@Overridepublic void work() {System.out.println("厨师正在炒菜");}
}
测试类:
public class Text {public static void main(String[] args) {Manage m = new Manage("001","zhangsan", 7843.5, 213.5);System.out.println(m.toString());m.eat();m.work();Cooker c = new Cooker();c.setId("002");c.setName("lisi");c.setSalary(6743);System.out.println(c.toString());c.eat();c.work();}
// Manage{bouns = 213.5}
// 吃米饭
// 经理正在管理其他人
// Employee{id = 002, name = lisi, salary = 6743.0}
// 吃米饭
// 厨师正在炒菜
}