注意事项:
1、多关注语法点的基本作用
2、思考、记忆、练习
3、自信!不要想短期内做什么
一、static
1、是什么
static静态,修饰成员变量、成员方法。内存中只存储一份,可以共享访问、修改。
2、调用方法
2种,类名.静态成员变量(推荐);对象.静态成员变量(不推荐)。
3、区分静态成员变量和实例成员变量
静态成员变量,属于类的,直接用类名去调用,可以共享的信息;
实例成员变量,属于某个实例对象的,必须用实例名去调用,每个对象都不同的信息。
package com.laogao.staticdemo;
public class User {
public static int onLineNum=11;//内存中只一份
private String name;
private int age;//私有的,通过getter\setter去调用修改
public static void main(String[] args) {
//输出静态成员变量
System.out.println(User.onLineNum);
System.out.println(onLineNum);//在类中,可以直接用名称调用静态成员变量
//创建实例对象
User user=new User();
user.onLineNum++;//调用静态成员变量
System.out.println(user.onLineNum);//输出静态成员变量
user.age=18;
user.name="ll";
System.out.println(user.age);//输出实例成员变量
}
}
4、static修饰成员变量的内存原理
(1)首先是将 类 加载到方法区,同步在堆内存中开辟一块存储相应的静态变量区(加载静态变量)。
(2)提main方法到栈里,在下边堆内存这个图里,可以清晰的看出来,实例成员变量(name、age)是属于每个对象的,而静态成员变量(onLineNumber)是属于类的。
看弹幕确实拓展了我的思考:
(1)用private,static还能共享吗?有个问题类似这样。
个人理解:static修饰的变量就是能共享、修改的,所以和前边的public、private没啥关系,public和private应该是该变量使用的范围吧,在本类里用,还是其他类也能用的问题。(不过static是共享的,那用private应该是没有必要的)
结合起来,大概就是public你按照调用的规范,想怎么用都行。private就有了限制,本类里用没什么问题,在类外边用或者通过对象调用这个静态成员变量就不行了,待验证。
(2)静态成员变量和全局变量,动态变量与静态变量,待学习。
5、static修饰成员方法的基本用法
静态成员方法,共享,归属于类,可以用类、对象访问;在类中,可以直接用方法名调用(实际是用类去调用的这个静态方法);
实例成员方法,属于对象,必须用对象去调用。
区分:
什么时候用static:共用功能,和对象没什么关系。
什么时候不用static:需要访问实例成员时,对象自己的行为。
6、修饰成员方法的内存原理
分析:先在方法区加载静态方法,提main方法在栈中运行,如果main中调用了静态方法,直接去方法区找,提到栈中执行。如果调用的是实例成员方法,会先找到堆内存中的对象,再通过对象中的引用地址找到方法。
7、注意事项(面试笔试)
(1)静态方法只能访问静态成员,不可以直接访问实例成员(如果创建一个对象,那可以访问)。
(2)实例方法可以访问静态成员,也可以访问实例成员。静态成员是共享的,当然可以访问。实例方法、实例变量都是属于当前对象的,都是用对象去调用,因此实例方法可以直接访问实例成员 。
(3)静态方法中不可以出现this关键词。理解:this代表当前对象,静态方法可以用类调用,可以用对象调用。如果静态方法用类去调用,那方法中出现的this就找不到当前对象了;如果静态方法是用对象调用的,那么静态方法中可以出现this,但这谁也不能保证每次都用对象去调用。
二、static应用知识:工具类util
1、好处
调用方便(直接用类名调用,不需要创建对象),提高代码复用。
2、工具类
里边都是静态方法,让开发人员共同使用。
3、要求
建议将工具类构造器私有化(装B必备)。
工具类构造器私有化,这样就无法创建工具类对象了。要想访问工具类中的静态方法,直接用类名,不能创建实例对象。
4、代码练习
package com.laogao.staticdemo;
/**
* 数组工具类
*/
public class ArrayUtil {
/**
* 构造器私有化
*/
private ArrayUtil(){
}
/**
* 输出整型数组
* @param arr
* @return
*/
public static String toString(int [] arr) {
//1、校验
if (arr==null){
return null;
}
String rs="[";
for (int i = 0; i < arr.length; i++) {
rs+=(i== arr.length-1?arr[i]:arr[i]+",");
}
rs+="]";
return rs;
}
/**
* 去掉最值,计算平均值
* @param arr
* @return
*/
public static double getAerage(double[] arr){
double max=arr[0],min=arr[0];
double sum=arr[0];
for (int i = 1; i < arr.length; i++) {
if(arr[i]>max){
max=arr[i];
}
if(arr[i]<min){
min=arr[i];
}
sum+=arr[i];
}
return (sum-max-min)/(arr.length-2);
}
}
三、static应用知识:代码块
代码块——类的五大成分之一(成员变量、方法、构造器、代码块、内部类),定义在类中方法外。
1、静态代码块
优先初始化静态资源,格式 static{} ,与类一起优先加载一次,自动触发执行。比main方法先执行。
2、构造代码块(实例代码块,少见)
属于对象,格式{} , 比构造器先执行,初始化实例资源(一般不用)。
package com.laogao.staticdemo;
public class StaticCode {
/**
* 静态代码块:初始化静态资源
*/
static {
System.out.println("调用静态代码块");
}
/**
* 无参构造器
*/
public StaticCode(){
System.out.println("====调用无参构造器=====");
}
/**
* 构造代码块,实例代码块,初始化实例资源
* 一般不用,了解
*/
{
System.out.println("调用实例代码块");
}
public static void main(String[] args) {
StaticCode staticCode=new StaticCode();
}
}
运行结果:
3、静态代码块应用案例
专业、优雅,只跑一次static{} 。
package com.laogao.staticdemo;
import java.util.ArrayList;
public class StaticCode {
//共享一副牌
public static ArrayList<String> cardList=new ArrayList<>();
/**
* 静态代码块:初始化静态资源
* 优先初始化静态资源,比main方法优先执行
*/
static {
System.out.println("调用静态代码块");
//所有数字
String[] nums={"2","3","4","5","6","7","8","9","J","K","A"};
//所有花色
String[] colors = {"♥", "♦", "♠", "♣"};
//遍历添加到卡片列表
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < colors.length; j++) {
String card=colors[j]+nums[i];
cardList.add(card);
}
}
cardList.add("大🃏");
cardList.add("小🃏");
}
public static void main(String[] args) {
System.out.println(cardList);
}
}
运行结果:
四、static应用知识:单例设计模式
1、设计模式:即最优的解决方案
(1)单例模式:永远只有一个实例对象。可以节省内存空间。
(2)饿汉单例模式:获取对象前已经准备好了一个对象。
步骤:先构造器私有化,再用静态变量存储一个对象(静态变量属于类,只加载一次)。
package com.laogao.staticdemo;
public class SingleInstance {
/**
* 饿汉单例模式:提前已经准备好一个实例对象
*/
//1、构造器私有化,不允许其他类创建本类对象
private SingleInstance(){
}
//2、静态成员变量,存储实例对象;静态的是可共享的,那用public就行
public static SingleInstance instance=new SingleInstance();
}
package com.laogao.staticdemo;
public class TestDemo {
public static void main(String[] args) {
// SingleInstance instance=new SingleInstance();//报错
SingleInstance instance=SingleInstance.instance;//类名直接调用静态成员变量
SingleInstance instance2=SingleInstance.instance;//类名直接调用静态成员变量
System.out.println(instance==instance2);//true
}
}
(3)懒汉单例模式:真正需要的时候,才去构建对象。
设计步骤:先构造器私有化,再定义一个静态成员变量负责存储一个对象,提供一个方法,返回单例对象。
package com.laogao.staticdemo;
public class SingleInstance {
/**
* 懒汉单例模式
*/
//1、构造器私有化,不允许其他类创建本类对象
private SingleInstance(){
}
//2、静态成员变量,存储实例对象;
// 此处用private,这样获取对象只能通过类所提供的get方法进行获取,防止直接过去报错
private static SingleInstance instance;
//3、提供一个static方法,返回单例对象,这样可以直接通过类名调用该方法
public static SingleInstance getInstance(){
if (instance==null){//之开辟一块内存,节省空间
instance=new SingleInstance();
}
return instance;
}
}
package com.laogao.staticdemo;
public class TestDemo {
public static void main(String[] args) {
// SingleInstance instance=new SingleInstance();//报错
SingleInstance instance=SingleInstance.getInstance();//类名直接调用静态成员变量
SingleInstance instance2=SingleInstance.getInstance();//类名直接调用静态成员变量
System.out.println(instance==instance2);//true
}
}
五、继承
1、概述、好处
概述:extends,类和类之间存在的父子关系,子类可以使用父类(超类)中的属性和方法。
好处:提高代码复用性,减少代码冗余,增强类的功能扩展性(子类很多功能可以直接继承自父类)。
2、设计规范、内存原理
设计规范:子类间相同特征定义在父类中,独有的定义在子类中。
案例:
父类:人
public class Student extends People{
private String couse;
public String getCouse() {
return couse;
}
public void setCouse(String couse) {
this.couse = couse;
}
public void listenFeedback(){
System.out.println(getName()+"填写了听课反馈~");
}
}
子类:学生
public class Student extends People{
private String couse;
public String getCouse() {
return couse;
}
public void setCouse(String couse) {
this.couse = couse;
}
public void listenFeedback(){
System.out.println(getName()+"填写了听课反馈~");
}
}
子类:老师
public class Teacher extends People{
private String department;
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public void questionPublic(){
System.out.println(getName()+"老师,发布了问题~");
}
}
测试类
public class TestDemo {
public static void main(String[] args) {
Student student=new Student();
student.setName("张三");
student.queryCouse();
Teacher teacher =new Teacher();
teacher.setName("李四");
teacher.questionPublic();
}
}
测试结果:
内存原理:
3、特点(面试)
(1)子类可以继承父类的属性和行为,但是子类不能继承父类的构造器
(2)java单继承模式,一个类只能继承一个直接父类
(3)Java不支持多继承、但支持多层继承
(4)Java中所有类都是Object类的子类
分析:
子类可以继承父类的私有成员,只是不能直接访问。
子类可以直接使用父类的静态成员(共享),但这应该不是继承。静态成员变量在内存中只有一份。
Object类是默认继承可以不写。
面试:为什么不支持多继承
加入两个父类中有相同的方法名,那用谁呢?Java是一种严谨的语言,不能有歧义
如果父类和父类的父类有相同方法,那就-->就近原则。
4、继承后:成员变量、成员方法的访问特点(笔试)
就近原则,先局部-->再子类成员变量-->再父类,找不到就报错。
(局部变量和成员变量重名情况下,如果一定要访问成员变量,可以加this;子类变量和父类变量重名情况下,如果一定要访问父类,加super)
5、继承后:方法重写
子类和父类的方法声明一样,在父类的某功能不能满足要求时,子类可以重写该功能。覆盖父类方法。
重写注解:加上@Oberride更优雅,告诉别人,这是一个重写的方法,如果报错说明这个方法没有重写成功。有重写校验的功能。更安全。
笔试:重写方法注意事项和要求
(1)重写的名字和形参列表必须一致!(这里可以回顾对比一下重载)
(2)私有方法不能被重写。
(3)子类重写父类方法时,访问权限必须大于或者等于父类(推荐写成和父类一致的权限,权限大小:缺省<protected<public)。
(4)子类不能重写父类的静态方法,如果重写会报错。(静态方法,整个类就这么共用一份)
6、继承后:子类构造器的特点
特点:子类先访问父类的无参构造器,在执行自己的构造器。
原因:可能会用到父类中的数据,因此先调用父类构造器初始化父类。
默认在子类构造器第一句是 super() ,调用父类无参数构造器。
7、继承后:子类构造器访问父类有参构造器
目的:将数据给父类有参构造器,初始化父类的一些数据。
super(参数……);//调用父类有参数构造器
调整窗口快捷方式:方便代码的编写 如下图:
注意事项:如果父类没有无参构造器,那会报错,因为子类默认调用父类的无参构造器。
解决办法:1、给父类写上无参构造器。2、子类中用super(参数……)调用父类有参数构造器。
8、this、super使用总结
练习:
教师类
package com.laogao.staticdemo;
public class Teacher extends People{
private String department;
private String label;
//无参数构造器
public Teacher(){
super();//默认
}
// 有参构造器
public Teacher(String department) {
//调用其他构造器
this(department,"公共课");//label默认Java
}
public Teacher(String department,String label){
this.department=department;
this.label=label;
}
public Teacher(String name, int age, String department) {
super(name, age);
this.department = department;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public void questionPublic(){
System.out.println(getName()+"老师,发布了问题~");
}
}
测试类:
package com.laogao.staticdemo;
public class TestDemo {
public static void main(String[] args) {
Teacher teacher1=new Teacher();
Teacher teacher2=new Teacher("计算机");
Teacher teacher3=new Teacher("会计","审计");
Teacher teacher4=new Teacher("李白",30,"传媒");
System.out.println(teacher2.getLabel());
System.out.println(teacher3.getLabel());
System.out.println(teacher4.getAge());
}
}
运行结果如下:
笔试:
子类通过 this(参数……) 去调用本类中的其他构造器。(一个类中可以有多个有参构造器,像方法重载,只是参数不同)
super()、this(参数……) 都要放在构造器的第一行,因此不能共同放在一个构造器中。
this(参数……) 在第一行时,将不再默认调用super(),而是通过this(参数……)先去找本类中的其他构造器,通过其他构造器再去默认调用父类构造器。