目录
一,多态
1.多态概述
1).定义: 指的是同一个对象,在不同时刻表现出来的多种形态。
2).多态含义:一种事物,多种形态。
3).代码体现:父类引用指向子类对象,父类引用调用方法,执行的是子类重写的方法
//Animal是父类,变量的类型是Animal就代表父类引用。
//Dog是子类,我们new的是Dog的对象就代表指向的子类的对象。
Animal a = new Dog();
4). 前提三要素:继承或实现,子类重写方法,向上转型(父类应用指向子类对象)
package com.itheima01;
/*
TODO: 多态
1. 含义: 一种事物,多种形态
2. 代码体现:
父类引用指向子类对象,父类引用调用方法,执行的是子类重写的方法
3. 前提三要素
1). 继承
2). 重写
3). 向上转型
*/
public class Demo {
public static void main(String[] args) {
//父类引用指向子类对象
// Animal a = new Cat();
Animal a = new Dog();
//父类引用调用方法,执行的是子类重写的方法
a.eat();
}
}
2.多态中成员的访问特点
a. 成员变量:编译看左边,执行看左边 (了解)
b. java的生命周期
1). 三个阶段
源码(source) -> 编译(compile) -> 运行 (runtime)
java文件 class字节码文件 Class对象(内存)
javac编译指令 java运行命令
2). 编译器 : 编译
把java源码转成java字节码,在这个过程中会对源码的语法和逻辑进行一定的校验
3). JVM : 运行
运行java字节码
c. 成员方法:编译看左边,执行看右边 (重点)
1). 赋值是运行阶段的事情,运行看右边
2). 编译在运行之前,无法预知运行的结果,只能看左边
注:为什么成员变量和成员方法的访问不一样呢?
因为成员方法有重写,而成员变量没有
public class Animal {
public int age = 40;
public void eat() {
System.out.println("动物吃东西");
}
public int getAge(){
return age;
}
}
public class Cat extends Animal {
//跟父类同名的变量
public int age = 20;
//子类特有属性
public int weight = 10;
//方法重写
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public int getAge(){
return age;
}
//子类特有方法
public void playGame() {
System.out.println("猫捉迷藏");
}
}
/*
测试类
*/
public class AnimalDemo {
public static void main(String[] args) {
//有父类引用指向子类对象
Animal a = new Cat();
//访问的是父类的age变量
System.out.println(a.age); //40
//编译报错: 编译看左边,a是父类类型,只看父类中是否有weight变量,没有就报错
//System.out.println(a.weight);
//访问的是子类特有方法,是因为方法重写机制
//父类的eat方法用于编译,子类的eat方法用于执行
a.eat();
//编译报错: 编译看左边
// a.playGame();
System.out.println(a.getAge());//20
}
}
3.多态的好处和弊端
a.好处:简化代码,提高了程序的扩展性。
具体体现:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子 类型参与操作,当需求变化的时候,代码改的越少,扩展性越强。
b.弊端 :不能使用子类的特有功能
注:应用场景
多态一般使用在方法的参数列表中.把方法的参数设置为父类类型,这样任意的子类 对象都可以传进来,这样的好处是不管增加了多少子类,我们都不需要增加方法,提高 代码的扩展性
4.多态中的转型
a.向上转型>从子到父:父类引用指向子类对象
Animal a = new Dog();
b.向下装型(强转: 强制类型转换)>从父到子 :父类引用转为子类对象
语法: 子类类型 变量名 = (子类类型)父类类型的变量
Dog g = (Dog)a;
向下转型有风险
1). 类型转换异常 ClassCastException
Cat类型的对象不能转换成Dog类型的变量
2). 规避风险: instanceof
如果a是Dog类型,result就是true,否则就是false
boolean result = a instanceof Dog;
package com.itheima03;
/*
TODO 多态的弊端
1. 弊端: 父类引用不能调用子类特有方法 (编译看左边)
2. 向下转型(强转: 强制类型转换)
1). 概念
I. 向上转型: 父类引用指向子类对象
Animal a = new Dog();
II. 向下转型: 子类引用指向父类类型引用
2). 语法
子类类型 变量名 = (子类类型)父类类型的变量
Dog g = (Dog)a;
3. 向下转型有风险
1). 类型转换异常 ClassCastException
Cat类型的对象不能转换成Dog类型的变量
2). 规避风险: instanceof
如果a是Dog类型,result就是true,否则就是false
boolean result = a instanceof Dog;
*/
public class Demo02 {
public static void main(String[] args) {
Dog dog = new Dog();
//喂狗,并且让狗看家
keepPet2(dog);
Cat cat = new Cat();
//喂猫
keepPet2(cat);
}
public static void keepPet2(Animal a){
a.eat();
//编译报错: 编译看左边, 父类引用不能调用子类特有方法
// a.lookDoor();
// boolean result = a instanceof Dog;
// if(result){
if(a instanceof Dog){
Dog g = (Dog)a;
g.lookDoor();
}
}
}
5.多态的内存图解
instanceof 它的作用是测试它左边的对象是否是它右边的类的实例, 返回 boolean 的数据类 型,如果是 结果为true,如果不是 结果为false
格式: if(对象 instanceof 类名/接口名){、、、 }
例如:
public static void userAnimal(Animal a){//Animal a = new Dog();
a.eat();
//如果传入的是只狗 就调用它的lookHome()//实例
if(a instanceof Dog){
Dog d = (Dog)a;
d.lookHome();
}
}
二,抽象类
1.抽象类概述
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类 必须定义为抽象类
//拥有抽象方法的类必须是抽象类
public abstract class Animal {
/*
public void eat() {
System.out.println("吃东西");
}
*/
//抽象方法: 没有方法体的方法
public abstract void eat();
}
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
}
public class Demo {
public static void main(String[] args) {
Animal a = new Dog();
//父类方法只用于编译,子类方法才用于执行
a.eat();
}
}
为什么要使用抽象?>当一个类中有一个方法,这个方法必须要让子类去重写,就可以把这个方法定 义成抽象方法.(理解即可)
2.抽象类的特点
1).抽象类和抽象方法必须使用 abstract 关键字修饰
public abstract class 类名 {};
public abstract void eat();
2).抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
3).抽象类不能实例化(不能被创建对象)
抽象类如何实例化呢?参照多态的方式,通过子类对象实例化,这叫抽象类多态。
4).抽象类的子类
要么重写抽象类中的所有抽象方法,要么是抽象类。
5).抽象类的主要作用: 所有的子类共性抽取
6).抽象类和普通类的区别:
普通类所拥有的,抽象类都有,而且还多了一个抽象方法
抽象类不能实例化
public abstract class A {
public void method(){
System.out.println("method");
}
public abstract void method02();
public abstract void method03();
}
//子类要么是抽象类
abstract class B extends A{
}
//子类要么重写所有的抽象方法
class C extends A{
@Override
public void method02() {
System.out.println("method02");
}
@Override
public void method03() {
System.out.println("method03");
}
}
public class Demo {
public static void main(String[] args) {
//抽象类不能实例化
//A a = new A();
}
}
3.抽象类的成员特点
1).抽象类成员变量可以是变量也可以是常量。
2).抽象类的构造方法
有构造方法,但是不能实例化
那么,构造方法的作用是什么呢?用于子类实例化时, 对父类数据进行初始化
3).抽象类的成员方法
可以有抽象方法:限定子类必须完成某些动作
也可以有非抽象方法:提高代码复用性
public abstract class A {
public int a;
public static final int AGE = 1;
public A() {
}
public A(int a) {
this.a = a;
}
//下定义
//所有A的子类对象必然有method01方法
public abstract void method01();
}
public class Demo {
public static void main(String[] args) {
System.out.println(A.AGE);
}
}
三,接口
1.接口类概述
扩展:# java的类型
a. 基本类型 byte int short long float double boolean char
b. 引用类型
1). class : 类
2). interface : 接口
3). annotation : 注解
4). enum : 枚举
概述:接口就是一种公共的规范标准,Java中的接口更多的体现在对行为的抽象
我们可以使用接口来定义一些规则(比如要求某个方法的方法名必须叫什么,方法 的参数列表必须是什么,方法的返回值类型必须是什么)
定义格式: public interface 接口名{}
//接口: 规范,标准
public interface Usb {
public abstract void chongDian();
}
//类实现接口: 继承
class Mouse implements Usb{
@Override
public void chongDian() {
System.out.println("鼠标在充电");
}
}
2.接口的特点
1).接口用关键字interface修饰 public interface 接口名 {}
2).类实现接口用implements表示 public class 类名 **implements** 接口名 {}
3).接口不能实例化
接口如何实例化呢?参照多态的方式,通过实现类对象实例化,这叫接口多态
多态的形式:具体类多态,**抽象类多态,接口多态**
多态的前提:有继承或者实现关系;有方法重写;有父(类/接口)引用指向(子/实现) 类对象
4). 接口的实现类 要么重写接口中的所有抽象方法,要么是抽象类
3.接口垫成员特点
1).接口的成员变量特点:
只能是常量
默认修饰符:**public static final**
2).构造方法: 接口没有构造方法,因为接口主要是扩展功能的,而没有具体存在
一个类如果没有父类,默认继承自Object类
3). 接口的成员方法特点:
只能是抽象方法
默认修饰符:**public abstract**
/*
TODO 接口的成员特点
1. 成员变量
1). 只能是常量
2). 默认修饰符: public static final
2. 成员方法
1). 只能是抽象方法(JDK8之前)
2). 默认修饰符: public abstract
3. 构造方法
没有!
快捷键: ctrl + i(implements) 提示所有未重写的抽象方法
*/
public interface A {
public static final int AGE = 1;
int AGE2 = 2;
public abstract void method01();
void method02();
}
abstract class B implements A{
@Override
public void method01() {
}
}
class C implements A{
@Override
public void method01() {
}
@Override
public void method02() {
}
}
4.类和接口的关系
1).类和类的关系
继承关系,只能单继承,但是可以多层继承
2).类和接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
3). 接口和接口的关系
继承关系,可以单继承,也可以多继承
/*
1. 类和类的关系: 继承 extends
Java的类只能单继承,不能多继承,可以多层继承
2. 类和接口的关系: 实现 implements
Java的接口支持多实现
3. 接口和接口的关系: 继承 extends
Java的接口支持多继承
*/
public class A {
}
//常见
class B extends A{
}
interface C{
}
interface D{
}
//常见
class E implements C,D{
}
//常见
class F extends B implements C,D{
}
interface G extends C,D{
}
5.抽象类和接口的区别
抽象类 : 变量,常量;有构造方法;有抽象方法,也有非抽象方法
接口 : 常量;抽象方法
类与类 : 继承,单继承
类与接口 : 实现,可以单实现,也可以多实现
接口与接口 : 继承,单继承,多继承
抽象类 : 对类抽象,包括属性、行为 满足 'is a' 的关系
接口 : 对行为抽象,主要是行为 满足 'have a'的关系
6.接口新增的方法
1).接口中默认方法的定义格式:
格式:public default 返回值类型 方法名(参数列表) { }
范例:public default void show1() { }
接口中默认方法的注意事项:
public可以省略,default不能省略
2). 接口中静态方法的定义格式:
格式:public static 返回值类型 方法名(参数列表) { }
范例:public static void show2() { }
接口中静态方法的注意事项:
3).接口中私有方法的定义格式:
格式1:private 返回值类型 方法名(参数列表) { }
范例1:private void show3() { }
范例1:private void show3() { }
格式2:private static 返回值类型 方法名(参数列表) { }
范例2:private static void show4() { }
接口中私有方法的注意事项:
//预告: 主要为JDK8引入函数式编程做铺垫
public interface A {
//JDK8: 默认方法
public default void method01(int a){
method05();
System.out.println(a);
}
//public默认省略
default void method02(){
method05();
System.out.println("method02");
}
//JDK8: 静态方法
public static void method03(){
System.out.println("method03");
}
// public默认省略
static void method04(){
System.out.println("method04");
}
//JDK9: 私有方法
private void method05(){
System.out.println("method05");
System.out.println("method06");
System.out.println("method07");
}
}
四,代码块(补充)
根据其位置和声明的不同,可以分为:
局部代码块
构造代码块
静态代码块
同步代码块(未来学)
package com.itheima13;
public class Student {
static{
System.out.println("静态代码块");
}
{
System.out.println("构造代码块");
}
public Student(){
System.out.println("构造方法");
}
}
package com.itheima13;
/*
TODO 代码块
1. 局部代码块(了解)
1). 写在方法内部的代码块
2). 作用: 限定变量的使用范围
2. 构造代码块(了解)
1). 写在成员位置的代码块
2). 特点: 创建对象时调用,优先于构造方法执行,每创建一个对象,就执行一次
3. 静态代码块 (重要)
1). 写在成员位置的静态代码块
2). 特点: 随着类的加载而执行,只执行一次
3). 作用: 适合资源初始化
*/
public class Demo {//类体 class body
public static void main(String[] args) {//方法体 method body
int a = 1;
{//代码块 code block
int b = 2;
}
// System.out.println(a);
// System.out.println(b); //不能用
Student s = new Student();
Student s2 = new Student();
}
}
五,内部类
1.内部类概述
1).内部类:就是在一个类中定义一个类。举例:在一个类A的内部定义一个类B,类B就 被称为内部类
2).内部类的定义格式:
public class 类名{
修饰符 class 类名{
}
}
//范例
public class 类名{
修饰符 class 类名{
}
}
3).内部类的访问特点:
2.内部类分类
按照内部类在类中定义的位置不同,可以分为如下两种形式
a. 在类的成员位置:成员内部类
b. 在类的局部位置:局部内部类
3.成员内部类
成员内部类,外界如何创建对象使用呢?
格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
范例:Outer.Inner oi = new Outer().new Inner();
4.局部内部类
a.局部内部类是在方法中定义的类,所以外界是无法直接使用,需要在方法内部创建对象 并使用
b.该类可以直接访问外部类的成员,也可以访问方法内的局部变量
5.匿名内部类
前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类
格式:
new 类名或者接口名() {
重写方法;
};
//范例
new Inter() {
public void show() {
}
}
本质:是一个继承了该类的子类匿名对象,或者是一个实现了该接口的实现类匿名对象
6.内部类在开发中的应用
需求:给按钮添加事件