mt_Day5:static与继承
static静态关键字
1.static成员变量
- static + 成员变量:该变量在内存中只存储一份,可以被共享访问、修改。
- 静态成员变量的访问
public class User {
/**
* 例子:在线人数定义为静态成员变量
*/
public static int onlineNumber=50;
//实例成员变量
private String name;
private int age;
}
public class staticFieldDemo1 {
public static void main(String[] args) {
//1.用类名访问静态成员变量,推荐
//User.onlineNumber
System.out.println(User.onlineNumber);
//2.用对象访问静态成员变量,不推荐
User u=new User();
System.out.println(u.onlineNumber);
}
}
2.static成员变量的内存
存在堆内存
3.成员方法分类
- 静态成员方法(无static修饰,归属于类),建议类名访问,也可以用对象访问
- 实例成员方法(有static修饰,归属于对象),只能用对象触发访问
4.static成员方法内存
存在方法区
5.static访问注意事项
- 静态方法只能访问静态成员,不能直接访问实例成员(可以创建对象间接访问实例成员)
- 实例方法可以访问静态成员,也可以访问实例成员
- 静态方法中不能出现this关键字(因为this是当前对象地址,静态方法可能是不由对象调用的)
工具类
无需创建对象,内部都是一些静态方法,每个方法完成一个功能
一次编写,处处可用,提高代码的重用性
//例子:生成验证码的重复类
public class util {
/**
* 工具类无需创建对象,所以将其构造器私有化
*/
private util(){
}
//静态方法
public static String creatCode(int n){
String code="";
String data="abcdefghijklmnopqrstyvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"1234567890";
Random r=new Random();
for (int i = 0; i < n; i++) {
int index=r.nextInt(data.length());
code+=data.charAt(index);
}
return code;
}
}
代码块
- 类的5大成分之一(成员变量、构造器、方法、代码块、内部类),定义在类中方法外
- 在Java类中,用{}括起来的代码称为代码块
静态代码块:
- 格式:static{}
- 特点:用static关键字修饰,随着类的加载而加载,自动触发,只执行一次
- 使用场景:在类加载时,做一些静态数据初始化操作,以便后续使用
public class staticCodeDemo1 {
//静态资源,如城市名,一副扑克牌
public static String city;
public static ArrayList<String> cards=new ArrayList<>();
//静态代码块
static {
//比main方法优先调用
//作用:初始化静态资源
System.out.println("静态代码块被执行了");
city="北京";
};
public static void main(String[] args) {
System.out.println("main方法被执行");
System.out.println(city);
}
}
/*
静态代码块被执行了
main方法被执行
北京
*/
构造(实例)代码块:(很少用)
- 格式:{}
- 特点:每次创建对象,调用构造器前,都会执行一次{}中的代码,在构造器执行前执行(顺序:父构造,实例代码块,子构造)
- 使用场景:初始化实例资源
public class staticCodeDemo2 {
private String name;
staticCodeDemo2(){
System.out.println("无参构造器被触发执行");
name="张三";
}
//实例代码块
{
System.out.println("实例代码块被触发执行");
}
public static void main(String[] args) {
staticCodeDemo2 a=new staticCodeDemo2();
System.out.println(a.name);
}
}
/**
* 实例代码块被触发执行
* 无参构造器被触发执行
* 张三
*/
静态代码块案例:
扑克游戏需要一份扑克牌
- 存储54张牌类对象的集合,静态的集合指挥家在一份
- 系统启动同时准备好54张牌的数据,可用静态代码块完成
public class staticCodeTest3 {
/**
* 定义一个静态集合,因为当前房间只需要一副扑克牌
*/
public static ArrayList<String> cards=new ArrayList<>();
/**
*main方法执行前,放入54张牌
* 如果放在main中,若main调用很多次,static内容也会被执行多次,但在静态代码块只执行一次
*/
static{
//点数
String[] sizes={"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
//花色
String[] colors={"♥","♠","♦","♣"};
//组合
for (int i = 0; i < sizes.length; i++) {
for (int j = 0; j < colors.length; j++) {
String card=sizes[i]+colors[j];
cards.add(card);
}
}
cards.add("大🃏");
cards.add("小🃏");
}
public static void main(String[] args) {
System.out.println("新牌:"+cards);
}
}
单例模式
- 保证系统中,应用该模式的这个类永远只有一个实例,即一个类只能创建一个对象
- 例如:任务管理器对象只需要一个就可以解决问题,可以节省内存空间
饿汉单例:
用类获取对象前,对象已经提前创建好
- 定义一个类,构造器私有
- 定义一个静态存储对象
public class singleInstence {
/**
* 使用饿汉单例来实现单例类
* 饿汉单例:在获取对向前,对象已经提前准备好一个
* 这个对象只能是一个,所以用静态成员变量记住
*/
public static singleInstence hunger=new singleInstence();
//因为对象只能有一个,构造器私有
private singleInstence(){
}
public static void main(String[] args) {
}
}
public class test1 {
public static void main(String[] args) {
singleInstence s1=singleInstence.hunger;
singleInstence s2=singleInstence.hunger;
System.out.println(s1==s2);//true
}
}
懒汉单例
真正需要该对象的时候,才去创建一个对象(延迟加载对象),防止你在创建对象后没使用浪费内存,所以用时才创建
类加载的时候,懒汉的方法在方法区,并没有在栈内存;当调用懒汉的getInstance()方法得到对象时,才会进入栈内存,这样就节约了一部分内存
- 第一个类,构造器私有
- 定义一个静态变量存储对象
- 提供一个返回单例对象的方法
public class singleInstace2 {
/**
* 懒汉单例
*/
public static singleInstace2 lazy;//=new singleInstace2();×,用时才创建对象,lazy地址为null
private singleInstace2(){
}
public static singleInstace2 returnlazy(){
if(lazy==null){
//第一次来拿对象:需要创建对象,即懒汉用时才创建
lazy=new singleInstace2();
}
return lazy;
}
}
继承
子类存储空间
一个子类对象分为父类空间和子类空间
继承的特点
- 子类继承父类的属性和行为,但不能继承父类的构造器
- Java是单继承模式,一个类只能继承一个父类
- Java不支持多继承,但支持多层继承
- Java中所有的类都是Object的子类
子类继承了父类的私有成员,但不能直接访问
子类可以访问父类的静态成员,但是以共享的形式,不算继承
多层继承,若方法重名,就近原则
继承后成员的访问特点
就近原则
public class test {
public static void main(String[] args) {
Dog d=new Dog();
d.run(); //就近调用子类的run方法:狗也可以跑
}
}
class Animal{
public void run(){
System.out.println("动物可以跑");
}
}
class Dog extends Animal{
public void run(){
System.out.println("狗也可以跑");
}
}
方法重写
子类中写一个与父类声明一样的方法,覆盖父类方法
@Override //重写校验注解,加上后,必须是正确重写,更安全
public class test {
public static void main(String[] args) {
newPhone p=new newPhone();
p.call();//可以打电话 还可以视频通话
}
}
class phone{
public void call(){
System.out.println("可以打电话");
}
}
class newPhone extends phone{
@Override //重写校验注解,加上后,必须是正确重写,更安全
public void call(){
super.call();
System.out.println("还可以视频通话");
}
}
注意事项和要求
- 重写方法的名称、形参列表与被重写方法的名称、形参列表一致
- 私有方法不能重写
- 子类重写父类方法时,访问权限必须大于或等于父类(缺省<protected<public)父:public void call() 子:private void call() 不可以重写
- 子类不可以重写父类的静态方法
子类继承父类构造器特点
子类中所有的构造器,默认都会先访问父类中的无参构造器,再执行自己
因为
- 子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据
- 子类初始化之前,一定要调用父类构造器完成父类数据空间的初始化,子类构造器前都默认有一个super()
子类构造器访问父类有参构造器
public class people {
private String name;
private int age;
people(){
}
public people(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class teacher extends people{
public teacher(String name,int age){
//调用父类的参数构造器,初始化继承父类的数据
super(name,age);
}
}
public class test {
public static void main(String[] args) {
teacher t=new teacher("张三",30);
System.out.println(t.getName());
System.out.println(t.getAge());
}
}
this关键字
例子:学生填写姓名、国籍信息,不填写国籍,国籍默认为中国
public class Student{
private String name;
private String nation;
public Student(String name){
this(name,"中国");
}
public Student(String name, String nation) {
this.name = name;
this.nation = nation;
}
}
this(…)与super(…)使用注意点
- 子类通过this(…)调用本类的其他构造器,本类的其他构造器通过super手动调用父类的构造器,最终还是会调用父类的构造器
- 注意:this(…),super(…)都只能放在构造器的第一行,二者不能共存在同一个构造器中
浙公网安备 33010602011771号