视频地址:https://www.bilibili.com/video/BV1Cv411372m
此笔记是 P94 - P104
1.静态关键字:static(掌握)
1.1 static的作用、修饰成员变量的用法
-
static关键字的作用
-
static是静态的意思,可以修饰成员变量,表示该成员变量只在内存中只存储一份,可以被共享访问、修改。
-
-
成员变量可以分为2类
-
静态成员变量(有static修饰,属于类,内存中加载一次):常表示如在线人数信息、等需要被共享的信息,可以被共享访问。
-
访问
类名.静态成员变量(推荐) 对象.静态成员变量(不推荐) // 同一个类中访问静态成员变量,类名可以省略不写 System.out.println(onLineNumber);
-
-
实例成员变量(无static修饰,存在于每个对象中):常表示姓名name、年龄age等属于每个对象的信息。
-
访问
对象.实例成员变量 //name是属于每个对象的,这个name相当于还没有加载。直接访问name,是访问那个的name根本就不知道 // System.out.println(name);
public class User{ // 在线人数信息:静态成员变量 public static int onLineNumber; // 实例成员变量 private String name; private int age; public static void main(String[] args){ // 1. 类名.静态成员变量 User.onLineNumber++; // 注意:同一个类中访问静态成员变量,类名可以省略不写 System.out.println(onLineNumber); // 2. 对象.实例成员变量 // System.out.println(name); //name是属于每个对象的,这个name相当于还没有加载。直接访问name,是访问那个的name根本就不知道 User u1 = new User(); u1.name = "Even"; u1.age = "17"; System.out.println(u1.name); System.out.println(u1.age); // 对象.静态成员变量(不推荐) u1.onLineNumber++; System.out.println(onLineNumber); //结果是:2 上面加了一次 } }
-
-
两种成员变量各自在什么情况下定义?
- 静态成员变量:表示在线人数等需要被共享的信息。
- 实例成员变量:属于每个对象,且每个对象信息不同时(name,age…等)
1.2 static修饰成员变量的内存原理
1.3 static修饰成员变量的基本用法
- 之前定义的方法有的有static修饰,有的没有,有什么不同?
- 成员方法的分类:
- 静态成员方法(有static修饰,属于类),建议用类名访问,也可以用对象访问。一般通用功能我们就定义成静态方法
- 实例成员方法(无static修饰,属于对象),只能用对象触发访问。
- 使用场景
- 表示对象自己的行为的,且方法中需要访问实例成员的,则该方法必须申明成实例方法。
- 如果该方法是以执行一个通用功能为目的,或者需要方便访问,则可以申明成静态方法。
public class Student{
private String name;
private int age;
/**
实例方法:无static修饰,属于对象,通常表示对象自己的行为,可以访问对象的成员变量
*/
public void study(){
//study属于对象的,name也属于对象的,他们在同一对象中,可以互相访问
System.out.println(this.name+"在好好学习!");
}
/**
静态方法:有static修饰,属于类,可以被类和对象共享访问
一般通用功能我们就定义成静态方法,与成员变量对象本身无关联
*/
public static void getMax(int a,int b){
System.out.println(a > b ? a : b);
}
public static void main(String[] args){
// 1. 类名.静态方法
Student.getMax(10,20);
// 注意:同一个类中访问静态成员 可以省略类名不写
getMax(10,20);
// 2. 对象.实例方法
// study(); //报错的!!!
Student s = new Student();
s.name = "Even";
s.study();
// 3. 对象.静态方法(不推荐)
s.getMax(10,20);
}
}
1.4 static修饰成员方法的内存原理
1.5 static实际应用案例:设计工具类
-
工具类
- 对于一些应用程序中多次需要用到的功能,可以将这些功能封装成静态方法,放在一个类中,这个类就是工具类。
- 工具类的作用:一是方便调用,二是提高了代码复用。
-
工具类原理和延伸
-
一次编写,处处可用。
-
建议将工具类的构造器私有,不让工具类对外产生创建对象。
-
为什么工具类中的方法不用实例方法做?
- 实例方法需要创建对象调用,此时用对象只是为了调用方法,这样只会浪费内存。
-
-
练习:定义数组工具类
1.6 static的注意事项总结[面试热点]
public class Test {
// 静态成员变量
public static int onLineNumber;
// 实例成员变量
private String name;
//静态方法
public static void getMax(){
// 1、静态方法可以直接访问静态成员,不能访问实例成员。
System.out.println(Test.onLineNumber);
System.out.println(onLineNumber);
inAddr();
// System.out.println(name);
// 3、静态方法中不能出现this关键字
// System.out.println(this);
}
public void run(){
// 2、实例方法可以直接访问静态成员,也可以访问实例成员
System.out.println(Test.onLineNumber);
System.out.println(onLineNumber);
System.out.println(name);
Test.getMax();
getMax();
sing();
// 实例方法中可以出现this
System.out.println(this);
}
// 实例方法
public void sing(){
System.out.println(this);
}
// 静态成员方法
public static void inAddr(){
System.out.println("我们在黑马程序员~~");
}
public static void main(String[] args) {
}
}
2.static应用知识:代码块(掌握)
2.1 代码块的分类、作用
-
代码块概述
- 代码块是类的5大成分之一(成员变量、构造器,方法,代码块,内部类),定义在类中方法外。
- 在Java类下,使用 { } 括起来的代码被称为代码块 。
-
代码块分为
-
静态代码块
- 格式:static{}
- 特点:需要通过static关键字修饰,随着类的加载而加载,并且自动触发、只执行一次且优先执行
- 使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续使用。
-
构造代码块(了解,用的少)
- 格式:{}
- 特点:每次创建对象,调用构造器执行时,都会执行该代码块中的代码,并且在构造器执行前执行。
- 使用场景:初始化实例资源。
-
2.2 静态代码块的应用案例
import java.util.ArrayList;
public class StaticCodeTest3 {
/**
模拟初始化牌操作
点数: "3","4","5","6","7","8","9","10","J","Q","K","A","2"
花色: "♠", "♥", "♣", "♦"
1、准备一个容器,存储54张牌对象,这个容器建议使用静态的集合。静态的集合只加载一次。
*/
// int age = 12;
public static ArrayList<String> cards = new ArrayList<>();
/**
2、在游戏启动之前需要准备好54张牌放进去,使用静态代码块进行初始化
*/
static{
// 3、加载54张牌进去。
// 4、准备4种花色:类型确定,个数确定了
String[] colors = {"♠", "♥", "♣", "♦"};
// 5、定义点数
String[] sizes = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
// 6、先遍历点数、再组合花色
for (int i = 0; i < sizes.length; i++) {
// sizes[i]
for (int j = 0; j < colors.length; j++) {
cards.add(sizes[i] + colors[j]);
}
}
// 7、添加大小王
cards.add("小🃏");
cards.add("大🃏");
}
public static void main(String[] args) {
System.out.println("新牌:" + cards);
}
}
- 静态代码块的作用是什么?
- 如果要在启动系统时对数据进行初始化。
- 建议使用静态代码块完成数据的初始化操作,代码优雅。
3.static应用知识:单例(掌握)
3.1 设计模式、单例模式介绍、饿汉单例模式
-
什么是设计模式(Design pattern)
- 设计模式是一套被前人反复使用、多数人知晓、经过分类编目的代码设计经验的总结,后来者可以直接拿来解决问题。
- 设计模式是软设计中的常见解决方案,好的设计模式可以进一步的提高代码的重用性。
-
单例模式
- 可以保证系统中,应用该模式的这个类永远只有一个实例,即一个类永远只能创建一个对象。
- 使用场景
- 任务管理器对象我们只需要一个就可以解决问题了,这样可以节省内存空间。
- 单例的实现方式
- 饿汉单例模式
- 懒汉单例模式
-
饿汉单例设计模式
-
在用类获取对象的时候,对象已经提前为你创建好了。
-
设计步骤:
- 定义一个类,把构造器私有。
- 定义一个静态变量存储一个对象。
public class SingleInstance1 { /** static修饰的成员变量,静态成员变量,加载一次,只有一份 2.定义一个公开的静态变量成员存储一个类的对象 饿汉:在这里加载静态成员变量的时候就会创建对象了。 public static int onLineNumber = 21; */ public static SingleInstance1 instance = new SingleInstance1(); /** 1、必须私有构造器:私有构造器对外不能被访问。 */ private SingleInstance1(){ } }
-
3.2 懒汉单例模式
-
在真正需要该对象的时候,才去创建一个对象(延迟加载对象)。
-
设计步骤:
- 定义一个类,把构造器私有。
- 定义一个静态变量存储一个对象。
- 提供一个返回单例对象的方法。
4.面向对象三大特征之二:继承
4.1 继承概述、使用继承的好处
-
什么是继承?
-
Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起父子关系。【继承是类与类之间的一种关系】
public class Student extends People {}
-
多个类继承单独的某个类,多个类就可使用单独的这个类的属性和行为了。
-
多个类称为子类(派生类),单独的这个类称为父类(基类 或超类)。
-
-
为什么要用继承?
- 使用继承的好处:提高代码复用。
-
继承格式
-
继承的关键字”extends“
public class 子类名 extends 父类名 {}
-
-
继承后子类的特点?
- 子类 继承 父类,子类可以得到父类的属性和行为,子类可以使用。
- Java中子类更强大
4.2 继承的设计规范、内存运行原理(理解)
-
继承设计规范:
- 子类们相同特征(共性属性,共性方法)放在父类中定义。
- 子类独有的的属性和行为应该定义在子类自己里面。
-
为什么?
- 如果子类的独有属性、行为定义在父类中,会导致其它子类也会得到这些属性和行为,这不符合面向对象逻辑。
4.3 继承的特点(重要)
-
子类可以继承父类的属性和行为,但是子类不能继承父类的构造器。【子类有自己的构造器,自己构造器构建自己对象就成,不需要继承父类的】
-
Java是单继承模式:一个类只能继承一个直接父类。
-
Java不支持多继承、但是支持多层继承。
- 子类 A 继承父类 B ,父类B 可以 继承父类 C
-
Java中所有的类都是Object类的子类。
- Java中所有类,要么直接继承了Object , 要么默认继承了Object , 要么间接继承了Object, Object是祖宗类。
-
Java只支持单继承,不支持多继承。
- 单继承:子类只能继承一个直接父类
- 不支持多继承:子类不能同时继承多个父类
-
子类是否可以继承父类的构造器?
- 不可以的,子类有自己的构造器,父类构造器用于初始化父类对象。
-
子类是否可以继承父类的私有成员?
- 可以的,只是不能直接访问,因为私有访问不了罢了。类似于你父亲有个保险柜,你肯定是继承的,只是不知道密码,访问不了。
-
子类是否可以继承父类的静态成员?
- 有争议的知识点。
- 子类可以直接使用父类的静态成员(共享)
- 继承的含义是指:你真正的把这个东西放到我对象空间里面了,属于我对象了。但静态的成员不是给到了子类,静态成员属于类本身的,只会加载一次,从这个角度看,他只属于某一个类,属于某一类谈不了继承。所以个人认为:子类不能继承父类的静态成员。(共享并非继承)
4.4 继承后:成员变量、成员方法的访问特点(理解)
-
在子类方法中访问成员(成员变量、成员方法)满足:就近原则
- 先子类局部范围找
- 然后子类成员范围找
- 然后父类成员范围找,如果父类范围还没有找到则报错。
-
如果子父类中,出现了重名的成员,会优先使用子类的,此时如果一定要在子类中使用父类的怎么办?
- 一定要中转,子类中再定一个方法。
- 可以通过super关键字,指定访问父类的成员。
- 格式:super.父类成员变量/父类成员方法
4.5 继承后:方法重写(掌握)
-
什么是方法重写?
- 在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。
-
方法重写的应用场景
- 当子类需要父类的功能,但父类的该功能不完全满足自己的需求时。
- 子类可以重写父类中的方法。
-
案例演示:
- 旧手机的功能只能是基本的打电话,发信息
- 新手机的功能需要能够:基本的打电话下支持视频通话。基本的发信息下支持发送语音和图片。
-
@Override重写注解
- @Override是放在重写后的方法上,作为重写是否正确的校验注解。
- 加上该注解后如果重写错误,编译阶段会出现错误提示。
- 建议重写方法都加@Override注解,代码安全,优雅!
-
方法重写注意事项和要求
- 重写方法的名称、形参列表必须与被重写方法的名称和参数列表一致。
- 私有方法不能被重写。
- 子类重写父类方法时,访问权限必须大于或者等于父类 (暂时了解 :缺省 < protected < public)
- 子类不能重写父类的静态方法,如果重写会报错的。
4.6 继承后:子类构造器的特点(重要)
-
子类继承父类后构造器的特点:
- 子类中所有的构造器默认都会先访问父类中无参的构造器,再执行自己。
-
为什么?
- 子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
- 子类初始化之前,一定要调用父类构造器先完成父类数据空间的初始化。
-
怎么调用父类构造器的?
- 子类构造器的第一行语句默认都是:super(),不写也存在。
4.7 继承后:子类构造器访问父类有参构造器
-
super调用父类有参数构造器的作用:
- 初始化继承自父类的数据。
-
如果父类中没有无参数构造器,只有有参构造器,会出现什么现象呢?
- 会报错。因为子类默认是调用父类无参构造器的。
-
如何解决?
- 子类构造器中可以通过书写 super(…),手动调用父类的有参数构造器。
4.8 this、super使用总结
-
案例需求:
- 在学员信息登记系统中,后台创建对象封装数据的时候如果用户没有输入学校,则默认使用“黑马培训中心”。
- 如果用户输入了学校则使用用户输入的学校信息。
- this(…)和super(…)使用注意点:
- 子类通过 this (…)去调用本类的其他构造器,本类其他构造器会通过 super 去手动调用父类的构造器,最终还是会调用父类构造器的。
- 注意:this(…) super(…) 都只能放在构造器的第一行,所以二者不能共存在同一个构造器中。