this关键字和super的区别
① 访问变量(方法)时不同
this.变量/方法:当前类的属性、方法
super.变量/方法:当前类父类的属性、方法
② 调用构造方法时:
this():调用本类的空参构造
super():调用父类的无参构造this()和super() 不能共存:this()需要写在构造方法的第一行,super()也要写在构造方法的第一行;
③ 表示的对象时不同
this:当前类的对象,或者是谁调用该方法,this就表示谁
super:当前类父类的对象,或者谁调用该方法,super就是调用者的父类对象
继承实际应用---抽象类
抽象类
当一个类中,出现只有对方法的声明、没有方法的具体实现,这样的方法被称为抽象方法,一旦类中出现了抽象方法,那么这个类就称为抽象类;
抽象类中不一定有抽象方法,抽象类中也可以存在普通方法;
抽象方法的定义方式
将以前定义普通方法时的大括号给省略的(方法没有方法体),并且使用关键字 abstract 对方法进行修饰格式:
权限修饰词 abstract 返回值类型 方法名(参数列表);
public abstract void getArea();
抽象类的定义
跟以前声明类的方式一样,只不过需要的权限修饰词后面加上 abstract
格式:
public abstract class 类名{
}
抽象类的使用场景
当使用继承的思想进行程序设计时,需要先进行共性的抽取,此时就有可能会有行为的抽取,在抽取行为时,因为每一个子类他的行为可能是不一样的,所以在超类中无法描述行为的具体实现过程;遇到这种时候我们就可以只抽取行为,不去实现行为的过程,将行为定义成抽象方法,将类定义为抽象类。
案例:程序员、项目经理、前台小姐姐练习修改
public abstract class Employee {
String name;
String id;
int age;
double work_age;
double salary;
String department;
public abstract void work();
}
public class Programmer extends Employee {
double money;
public void work() {
System.out.println("撸代码");
}
}
public class Manager extends Employee{
double money;
public void work(){
System.out.println("瞎转悠");
}
}
public class Young_Sister extends Employee{
public void work() {
System.out.println("接待客户");
}
}
抽象类使用注意事项
① 抽象类可以被普通继承,也可以被抽象类继承
普通继承抽象类:系统会强制要求重写抽象类中的抽象方法
抽象类继承抽象类:可以不用重写父类的抽象方法(抽象类不能使用传统的方式创建对象)
抽象类不能使用 类名 对象名 = new 类名();这种方式创建对象
② 如果抽象类被抽象类继承,想要创建子类对象
a. 再创建一个普通类来继承抽象类,创建子类的对象来访问抽象类中的方法
b. 使用匿名内部类或者兰姆达表达式来快速创建抽象类的对象
③ 抽象类中可以定义变量,也拥有构造方法,但是不能直接使用抽象类的构造方法来实例化对象;
在一个类中,判断其有没有构造方法的方式是看在这个类中是否可以定义变量(构造方法就是用来给变量进行初始化赋值的,有变量就证明需要初始化赋值,所以就需要有构造方法)
继承总结
① java中只允许单继承或者多层继承,不允许多继承
单继承:一个孩子只能有一个亲爹,一个子类同一时间只能存在一个父类
多层继承:a extends b extends c extends d,a可以是b的子类,b可以是c的子类,c可以是d的子类
多继承:a extends b,c,java中不允许这样做;因为多个父类中可能存在相同的方法,如果同时继承子类就没办法 区分到底使用哪个父类中的方法
② 继承的过程中,构造方法不能被继承
③ 继承中进行成员方法的访问时:
a. 如果子类和父类中都定义了不同的方法,那在进行访问时,父类只能访问父类中定义的方法,子类可以访问父类和子类中定义的方法
b. 如果父类中的方法和子类的方法相同(方法的重写),那么在访问时,子类对象访问的结果是子类重写后的结果
代码块 ---- 属性或者是局部变量的赋值
① 局部代码块(局部/成员变量)
a. 在方法中定义
b. 格式:{}
案例:
public class Programmer extends Employee {
double money;
public void work() {
}
int i = 100;
money = 1000;
}
System.out.println("撸代码,挣了"+money);
}
}
c. 使用局部代码块的好处:
1. 限定变量的生命周期,一旦代码块执行结束,其中定义的变量就会被系统回收
2. 在代码块内进行的成员变量的赋值,在代码块结束之后仍然存在
② 构造代码块(属性)
a. 定义在类中方法外
b. 定义的格式:{}
c. 案例
public class Programmer extends Employee {
double money;
{
money = 1000;
}
public void work() {
System.out.println("撸代码,挣了"+money);
}
}
d. 构造代码块会比构造方法先执行
e. 构造代码块的使用:
1. 无需编程人员调用,由JVM自动调用
2. 每一个创建对象都会先执行构造代码块的内容
3. 编程时,如果有的数据需要在创建对象之前就有,就在构造代码块中进行赋值
③ 静态代码块(静态的属性,会比main方法还要先执行)
a. 类中方法外
b. 格式:static { }
c. 案例:
public class Image_Utils {
public static BufferedImage image = null;
static {
try {
image = ImageIO.read(Image_Utils.class.getResource(""));
}
catch (IOException e) {
e.printStackTrace();
}
}
}
内部类 ---- 更好的进行代码的封装、快速创建对象
① 分类
a. 局部内部类(定义在方法中)
格式:
class 内部类类名{
属性;方法;
}
b. 成员内部类(类中方法外)
格式:
class 内部类类名{
属性;方法;
}
c. 匿名内部类
功能:快速的创建抽象类或者接口的对象(要有继承或者实现的关系)
格式:
new 抽象类、接口(){
需要去实现抽象类或者接口中所有的抽象方法(方法的重写)
}.属性(方法)
匿名内部类的应用
① 当一个抽象类或者是接口需要创建对象时
② 当接口或者是抽象类的对象作为方法的参数时(常遇)
public abstract class Animal {
public abstract void sayHello();
}
public class Test_Animal {
public static void sayHello(Animal a){
a.sayHello();
}
public static void main(String[] args) {
sayHello(new Animal() {
public void sayHello() {
System.out.println("旺旺旺");
}
});
}
}
权限修饰词 ---- 设置方法或者是属性以及类的访问权限
final关键字
修饰内容 | 作用 |
变量 | 将变量变成常量 |
方法 | 表示该方法时一个终态的方法,不能被重写,可以被继承 |
类 | 表示这个类是一个终态类,该类不能被继承 |
多态
多态的概念
事物的多种形态,不同形态的时候所具备的功能不一样
对象的多态:同一个对象在不同的环境中具有不同的形态,功能也不同
行为的多态:可以是相同的也可以是不同对象,但是他们都具有相同的行为,行为所产生的效果也可以不同
实现多态的前提
① 必须要有继承(类或者抽象类)或者是实现(接口)的关系
② 必须存在方法的重写
③ 需要有父类引用子类的对象(去调用方法)
多态的代码实现
/// 超类,可以是普通类,抽象类,接口
public class Animal {
int age;
String name;
public void eat(){
System.out.println("这是animal的eat方法");
}
}
// 一般是一个普通类,让 animal 和 dog 产生继承关系
public class Dog extends Animal{
// 子类重写父类的方法
public void eat(){
System.out.println("这是dog的eat方法");
}
}
// 测试类
public class Test01 {
public static void main(String[] args) {
// 父类引用子类的对象
Animal animal = new Dog();
animal.eat();
}
}
使用父类引用子类对象时访问成员
① 成员变量:编译运行看左边
无论是编译还是运行都是以父类中的成员为准
② 成员方法:编译看左边,运行看右边:
编译期间查看父类中是否有方法的定义,如果有,编译成功,最终的执行结果却是以子类中重写后的方法为准;
如果父类中没有定义此方法,编译失败,程序报错
多态转型
向上造型 - 自动完成
父类引用子类对象
父类 父类对象名 = new 子类();
向下转型(强制类型转换)
一定先有向上造型、再向下转型
父类 父类对象名 = new 子类();
子类 对象名 = (子类)父类对象名;
向下转型的注意事项
① 如果,一个父类有多个子类,那么在向下转型之前最好先做一下类型的判断,如果类型匹配在进行转型,否则容易出现异常(类型转换异常 - ClassCastException)
② 在转型之前使用 instanceof 运算符进行类型的判断object instanceof 类
如果 object 属于类,结果就为true,
否则结果为false