第七章 面向对象
7.5 构造方法
1.定义:
方法名和类名相同,没有返回值类型
Person p = new Person();
new关键字实际上是在调用一个方法,这个方法叫构造方法(构造器)
2.构造器的格式:
[修饰符] 类名(){}------无参构造
[修饰符] 类名(形参类型 变量名1,形参类型 变量名2...){方法体}------有参构造
每一个类都会有一个默认的无参构造方法,当写了一个有参构造,默认无参构造就会消失
3.构造器和方法的区别:
1.没有方法的返回值类型
2.方法体内部不能有return语句
3.构造器的名字必须跟类名一样
4.构造器的作用:
不是为了创建对象,因为在调用构造器之前,这个对象就已经创建好了,并且属性有默认的初始化的值。
调用构造器的目的是给属性进行赋值操作的。
注意:我们一般不会在空构造器中进行初始化操作,因为那样的话每个对象的属性就一样了。
5.构造器的重载
1.一般保证空构造器的存在,空构造器中一般不会进行属性的赋值操作
2.一般我们会重载构造器,在重载的构造器中进行属性赋值操作
3.在重载构造器以后,假如空构造器没写,系统也不会给你分配默认的空构造器了,那么你要调用的话就会出错了。
4. 当形参名字和属性名字重名的时候,会出现就近原则:
在要表示对象的属性前加上this.来修饰 ,因为this代表的就是你创建的那个对象
7.6 this
/*this关键字用法:
1.this可以修饰属性:
总结:当属性名字和形参发生重名的时候,或者属性名字和局部变量重名的时候,都会发生就近原则,如果直接使用变量名字的话就指的是离的近的那个形参或者局部变量,这时候想要表示属性的话,在前面要加上:this.修饰
如果不发生重名问题的话,访问属性也可以省略this.
2.this可以修饰方法:
总结:在同一个类中,方法可以互相调用,this.可以省略不写。
3.this可以修饰构造器:
总结:同一个类中的构造器可以相互用this调用,注意:this修饰构造器必须放在第一行*/
public Person(int age,String name){
this(age);
this.name = name;
}
public Person(int age){
this.age = age;
}
7.7 static
- static可以修饰:属性,方法,代码块,内部类。
2.static修饰属性;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gnkAB7PG-1627111404868)(D:\QF_workspace\周总结\第三周总结.assets\image-20210724102110370.png)]
static修饰属性总结:
(1)在类加载的时候一起加载入方法区中的静态域中
(2)先于对象存在
(3)访问方式: 对象名.属性名 类名.属性名(推荐)
static修饰属性的应用场景:某些特定的数据想要在内存中共享,就可以用static修饰的属性
属性:
静态属性 (类变量)
非静态属性(实例变量)
3.static修饰方法
public class Demo {
int id;
static int sid;
public void a(){
System.out.println(id);
System.out.println(sid);
System.out.println("------a");
}
//1.static和public都是修饰符,并列的没有先后顺序,先写谁后写谁都行
static public void b(){
//System.out.println(this.id);//4.在静态方法中不能使用this关键字
//a();//3.在静态方法中不能访问非静态的方法
//System.out.println(id);//2.在静态方法中不能访问非静态的属性
System.out.println(sid);
System.out.println("------b");
}
public static void main(String[] args) {
//5.非静态的方法可以用对象名.方法名去调用
Demo d = new Demo();
d.a();
//6.静态的方法可以用 对象名.方法名去调用 也可以 用 类名.方法名 (推荐)
Demo.b();
d.b();
7.8 代码块
在Java中,使用{}包裹棋起来的内容,成为代码块!
分类:
局部代码块 :在方法定义中使用 ,作用:限定局部变量的生命周期
构造代码块:在类的成员位置(类中,方法外),使用{}包裹起来 作用:给类中的一些成员进行数据初始化
静态代码块:
在类的成员位置,直接使用 static{},特点:随着类的加载而加载,优先于对象存在!
作用:也可以通过static代码块,静态代码块就加载一次!
优先级:
静态代码块> 构造代码块 > 构造方法
7.9 包
包名定义:
(1)名字全部小写
(2)中间用.隔开
(3)一般都是公司域名倒着写 : com.jd com.baidu
(4)加上模块名字:
com.jd.login com.jd.register
(5)不能使用系统中的关键字:nul,con,com1---com9.....
(6)包声明的位置一般都在非注释性代码的第一行:
package com.test1;
总结:
(1)使用不同包下的类要需要导包: import **.*.*; 例如:import java.util.Date;
(2)在导包以后,还想用其他包下同名的类,就必须要手动自己写所在的包。
(3)同一个包下的类想使用不需要导包,可以直接使用。
(4)在java.lang包下的类,可以直接使用无需导包:
(5)IDEA中导包快捷键:alt+enter
可以自己设置自动导包
(6)可以直接导入*:
7.10 继承
1.继承的概念:
将多个类的共性内容抽取到一个独立的类中,然后这多个类和独立的这个类产生一种关系: 继承关系
关键字: extends
class Fu{}
书写格式 :class Zi extends Fu{}
继承的好处:
1)提高代码的维护性
2)提高代码的复用性
3)让类和类之间产生的关系,是"多态的前提条件"
2.继承(类)的特点:
1)类与类之间的继承关系,只支持单继承
格式
class 子类名 extends 父类名{}
2)支持多层继承
3.继承中使用的注意事项:
1)子类继承父类:可以继承父类的非私有的成员,私有的成员外界不能访问的,只能在本类中访问
但是可以通过公共方法间接访问
2)构造方法是不能被继承的,但是子类可以间接通过 super关键字访问父类的构造方法
4.一个类的组成
成员变量
构造方法
成员方法
继承中,每一个成员变量的关系问题
成员变量
a)子类继承父类,如果子类中的成员变量名称和父类的成员变量名称不一致,分别访问即可!
b)子类继承父类,如果子类的成员变量名称和父类的成员变量名称一致:如何访问
1)首先在子类的局部位置找,是否存在局部变量名称,如果有,就使用
2)如果没有,就在子类的成员位置找,是否存在这个变量,如果存在,就使用
3)如果在子类的成员位置中没有找到,直接在父类的成员位置中找,如果有,就是使用!
4)如果父类的成员位置都没有,就没有这个变量,报错
遵循一个原则:就近原则
7.11 super
1.super:指的是:父类的
super可以修饰属性,可以修饰方法;
在子类的方法中,可以通过 super.属性 super.方法 的方式,显示的去调用父类提供的属性,方法。 在通常情况下,super.可以省略不写:
在特殊情况下,当子类和父类的属性重名时,你要想使用父类的属性,必须加上修饰符super.,只能通过 super.属性来调用
在特殊情况下,当子类和父类的方法重名时,你要想使用父类的方法,必须加上修饰符super.,只能通过 super.方法来调用
super修饰构造器:
其实我们平时写的构造器的第一行都有:super() 作用:调用父类的空构造器,只是我们一般都省略不写
(所有构造器的第一行默认情况下都有super(),但是一旦你的构造器中显示的使用super调用了父类构造 器,那么这个super()就不会给你默认分配了。如果构造器中没有显示的调用父类构造器的话,那么第一行 都有super(),可以省略不写)
2.this和super 的区别
this:代表的当前类对象的地址值引用
super:代表的父类对象的地址值引用(代表父类的空间标识)
访问成员变量
this.变量名; 访问的本类中的成员变量
super.变量名; 访问的是父类的成员变量
访问构造方法:
this() ; 访问本类的无参构造方法
super() ;访问的父类的无参构造方法
this(xxx);访问的本类的有参构造方法
super(xxx);访问的父类的有参构造方法
成员方法:
this.方法名();访问的是本类的成员方法
super.方法名() ;访问的是父类的成员方法
3.在构造器中,super调用父类构造器和this调用子类构造器只能存在一个,两者不能共存:
因为super修饰构造器要放在第一行,this修饰构造器也要放在第一行:
7.12 多态
一个事物在不同时刻不同形态
1.多态的前提条件:
1)必须存在继承关系 (extends)
2)必须存在方法重写
子类需要覆盖父类的功能
Animal
eat():"动物都需要吃饭..."
Cat
eat() "猫吃鱼"
3)必须有父类引用指向子类对象
class Fu{}
class Zi extends Fu{
//存在重写
}
格式: Fu fu = new Zi() ;
2.多态的成员访问特点:
Fu fu = new Zi() ;
1)针对成员变量的访问问题:
编译看左,运行看左
2)针对多态中的成员方法的访问问题: 我们所说的成员变量/成员方法----非static
编译看左,运行看右
3)如果成员方法是静态方法:(静态成员方法 算不上方法重写,直接可以类名来访问,跟类相关的方法)
编译看左,运行看左
4)构造方法:
存在继承关系: 还需要让父类先初始化,然后再子类进行数据初始化!(分层初始化!)
3.多态的好处:
1)提高代码的复用性:由继承保证
2)提高了代码的扩展性:由多态保证
Fu fu = new Zi() ; 父类引用可以指向子类对象
4.多态的弊端:---(向下转型)
不能访问子类的特有功能 (Fu f = new Zi())
f.方法名() ;报错了. 父类中没有子类特有功能!
如何解决多态的弊端?
"向下转型"
多态的第三个前提条件:
Zi z = (Zi)f ; 还原成子类型
强转类型转换: 目标类型 变量名 =(目标类型)初始化值;
5.多态的方式:
要使用向下转型,前提必须有父类引用指向子类对象 Fu f = new Zi() ;
遵循向下转型的格式:
Zi z = (Zi)f; 必须心里清楚堆内存存储的类型....
向下转型使用不当,就出现java.lang.ClassCastException:类转换异常: (属于运行时期异常)
当前堆内存中的实例不是该类型时,就会出现问题!
7.13 抽象类
1.抽象类:
现实世界事物中,某个事物是比较概括性,描述为抽象事物,只有具体的事物,才具备具体的功能;
将某个事物中的一些功能仅仅给出声明即可,没有方法体----->抽象方法---->此时这个类必须为抽象类!
举例:
动物都需要吃和睡
只要看到具体的动物类:猫类/狗类,才具备吃和睡的功能
将动物类中的吃和睡给出一个声明:加入一个关键字 abstract:抽象方法
动物类----->抽象类
抽象的关键字 :abstract关键字
2. 抽象方法的格式;
权限修饰符(一般情况都是public) abstract 返回值类型 方法名(形式参数列表) ;
抽象类的格式:
abstract class 类名{}
抽象类的特点:
1)有抽象方法的类一定是抽象类
2)抽象类中不一定只有抽象方法 ,还可以非抽象方法(有方法体)
3)抽象类不能实例化---->意思:不能创建对象
如何实例化呢:通过具体的子类进行实例化(进行对象的创建),
抽象类多态 Fu fu = new Zi() ;Fu类型 抽象类型
4)抽象类的子类有两种情况:
1)目前来说:如果抽象类的子类都是抽象类---毫无意义 因为子类也不能new ,除非再有具体的子类
2)抽象类的子类具体类---才能new 抽象多态的形式 Fu fu = new Zi() ;
抽象类的核心宗旨:就是强制子类必须完成的事情(要将父类中的所有的抽象方法必须重写,否则报错!)
面试题:
一个类中没有抽象方法,那么将这个类定义为抽象类的意义何在?
意义:为了不让它直接实例化!
如何实例化:
情况1)直接就有具体的子类
情况2)间接的有具体的子类
可能:某个功能的返回值是它本身----->功能里面的逻辑可能就是在new 最具体的子类!
如 JDK提供了 Calendar: 日历类 :就是抽象类
不想让Calendar直接new,通过一个静态的功能,返回值是当前类本身
abstract和哪些关键字冲突?
private冲突:
私有的方法,只能在本类中访问,加入abstract目的需要被子类重写,需要调用子类的功能!
static冲突:
静态方法随着类的加载而加载,而静态方法---算不上重写,所以它的访问
通过类名.方法名()---->而抽象方法没有方法体
final冲突
被final修饰的成员方法是不能被重写的,而加入abstract的方法需要被重写的!
abstract能够跟的关键字
public
默认修饰符
protected:受保护的 (范围:同一个包下的当前类或者子类中或者不包下的子类)
abstract一般在类上使用---->抽象类
在方法上使用---->抽象方法
可以在接口中使用
7.14 接口
1.接口---->它的本质就是体现一个现实世界事物所具有的的额外的扩展功能!
定义格式: interface 接口名{} ------>接口名遵循"标识符规则"---->大驼峰命名法
2.接口中的方法:不能有方法体,隐藏public abstract关键字,只能是抽象方法,不能有方法体
3.接口的特点:
1)不能实例化(不能创建对象)
2)如何实例化
接口实例化: 通过接口的子实现类(一定是具体类)进行实例化----接口多态(使用时最多的!)
子实现类和接口的关系: implements 实现关系
接口的子实现类如果是抽象类----->肯定要存在抽象类的具体的子类,否则都不能实例化!
4.接口的子实现类的命名规则:
开发中--->在接口名的后面+Impl:子实现类
interface Inter{}
class InterImpl implements Inter{
}
举例:
定义接口:UserDao (dao: Data Access Object :数据访问对象)
5.针对用户操作的接口
public abstract boolean login(String usrename,String password) ;//登录功能
public abstract void register(User user) ; //注册功能
6.用户操作接口实现类:UserDaoImpl implements UserDao
将login和register实现了---完成业务需求!
7.接口的成员特点:
1)接口中的成员方法:只能是抽象方法,默认的修饰符:public abstract(可以省略不写)
2)接口没有构造方法
3)接口的成员变量只能是常量:
存在默认修饰符:public static final (可以省略不写)
8. 类
具体类 class 类名{}
抽象类 abstract class 类名{}
接口 inteface 接口名{}
9.类与类之间的关系: extends 继承关系
只支持单继承,不支持多继承,但是可以多层继承
类和接口的关系: implements关系:实现关系
一个类继承另一个类的同时,可以实现多个接口,中间逗号给隔开
接口与接口之间: extends:继承关系
不仅支持单继承,也可以多继承,中间使用逗号隔开
7.15 内部类
1.内部类:
在一个类中可以定义另一个:
在类A 中定义了类B,将类B就称为类A的内部类,类A就是外部类!
成员内部类:
在一个类的成员位置中定义了另一个类
内部类可以访问外部类的成员,包括私有!
2.外部类如何直接访问内部类的成员方法?
格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
3.关于我们成员内部类的修饰符:
在成员内部类上面---加入private修饰:为了数据的安全性,它的访问---就要外部类的公共访问间接访问...
间逗号给隔开
接口与接口之间: extends:继承关系
不仅支持单继承,也可以多继承,中间使用逗号隔开
## 7.15 内部类
1.内部类:
在一个类中可以定义另一个:
在类A 中定义了类B,将类B就称为类A的内部类,类A就是外部类!
成员内部类:
在一个类的成员位置中定义了另一个类
内部类可以访问外部类的成员,包括私有!
2.外部类如何直接访问内部类的成员方法?
格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
3.关于我们成员内部类的修饰符:
在成员内部类上面—加入private修饰:为了数据的安全性,它的访问—就要外部类的公共访问间接访问…