2023年11月26日20:11:11
文章目录
- Java进阶(第二期)
- 一、package包的概念
- 二、抽象类和抽象方法(abstract)
- 2.1 使用
- 2.1 抽象类注意事项
- 三、接口
- 3.1 接口的定义格式
- 3.2 接口成员特点
- 3.3 类和接口的关系
- 3.4 接口和抽象类的对比
- 四、多态
- 4.1 多态的前提条件
- 4.2 对象多态
- 4.2 行为多态:
- 4.3 多态的成员访问特点
- 4.4 多态的转型技术
- 4.5 多态中的转型问题
- 五、综合练习:
Java进阶(第二期)
一、package包的概念
- package包,其实就是管理类的文件夹,用来存放文件类的。
- 只需要注意,同类名不同包的情况下,重复的类名,需要使用带包名访问。
二、抽象类和抽象方法(abstract)
2.1 使用
抽象类:抽象类其实就是特殊的父类
抽象方法存活在抽象类中,并且继承后的子类必须重写抽象方法
-
+ 抽象方法的定义格式: + public abstract 返回值类型 方法名(参数列表); + 抽象类定义格式: + public abstract class 类名 {}
- 问题:特殊在哪里?
- 回答;内部允许编写抽象方法
- 问题:什么是抽象方法?
- 回答:当我们将其共性的方法,抽取到父类之后,发现这个方法中无法给出具体明确(描述不清),而且这个方法,还是子类必须要有的方法,就可以设计为抽象方法。
-
看下面代码:这样设计完全不合理,我想抽取到父类中,让两个动物子类继承父类。里面的方法通过父类继承。但是我发现,方法都是一样的,就是里面的逻辑不一样,此时就得用到了抽象类和抽象方法:
不使用抽象类的代码如下:
package com.liujintao.demo; public class Abstrcte { public static void main(String[] LiuJinTao) { } } class Animal { public void eat () { System.out.println("我是吃饭的方法"); } } class dog { public void eat () { System.out.println("吃骨头"); } } class pig { public void eat () { System.out.println("吃食料"); } }
使用抽象类和抽象方法后的代码如下:
package com.liujintao.demo;
public class Abstrcte {
public static void main(String[] LiuJinTao) {
}
}
abstract class Animal {
public abstract void eat (); // 抽象方法必须存在抽象类中!!!
}
class dog extends Animal {
public void eat () {
System.out.println("吃骨头");
}
}
class pig extends Animal {
public void eat () {
System.out.println("吃食料");
}
}
- 经过改造,这就使用了抽象方法和抽象类实现了功能,让子类自己重写,补充些就滚蛋。
2.1 抽象类注意事项
- 抽象类不能实例化:
-
- 如果抽象类允许创建对象,就可以调用内部没有方法体的抽象方法了,不合理。
- 抽象类存在构造方法:
- 子类通过super方法进行访问父类构造方法
- 抽象类中可以存在普通方法:
-
- 因为抽象中,除了抽象方法外,的普通方法,子类可以通过继承使用父类中的方法
- 抽象类的子类:
-
- 要么重写方法抽象类中的所有抽象方法。
- 要么就让子类自己变成抽象类
-
三、接口
接口:体现的思想是对规则的声明
,Java中的接口更多体现的是对行为的抽象(抽象方法)
- 思路:
如果发现一个类,所有的组成,都是抽象方法
-
- 不能有成员变量
- 不能有普通的方法
- 这种类,我们就会将他设计为Java中的接口,因为现在这个类存在的唯一价值,就是声明规则。给需要的接口的使用者命名规则。
3.1 接口的定义格式
和定义类很像:
interface 接口名 {}
注意:接口不允许实例化。
接口和类之间是实现关系,通过implements关键字来完成接口的实现(和继承父级一样的写法)
class 类名 implements 接口名 {}
实现类 (也就是接口的子类)
- 要么重写接口中的所有抽象方法。
- 要么将实现类变成抽象类(继承后的抽象方法就必须存活在抽象类中)
第一种使用接口的方式(实现类中,重写抽象方法)
/**
* 定义一个接口
*/
interface Inter {
public void method ();
public void show ();
}
// 第一中使用接口的方法,使用接口(实现类)
class demoClass implements Inter {
// 1. 要么将接口里面的规则(抽象方法)全部重写
public void method() {
System.out.println("我是实现类中的 method方法");
}
public void show () {
System.out.println("我是实现类中的 show方法");
}
}
第二种使用接口的方式(将实现类变成抽象类) 不推荐使用
/**
* 定义一个接口
*/
interface Inter {
public void method ();
public void show ();
}
// 接口的第二种使用方法(变成抽象类,让其他类继承我的实现类)
abstract class Demo implements Inter {
// 要么将这个实现类变成抽象类
}
class Test extends Demo {
public void method () {
}
public void show () {
}
}
3.2 接口成员特点
- 成员变量: 只能定义常量,因为系统会默认加上三个关键字:
public static final
- 这三个关键字没有顺序关系
- 所以接口定义的时候,遵循static 和 final的使用规则。
-
成员方法:只能是抽象方法,因为系统会默认加入两个关键字
public abstract
-
接口中没有构造方法
3.3 类和接口的关系
1、 类和类之间的关系只能单继承,或者多层继承(前面有讲过),这里展示一个类继承多个类:
package com.liujintao.demo;
public class InterfaceDemo02 {
public static void main(String[] LiuJinTao) {
}
}
// 定义一个抽象父类
abstract class Fu1 {
// 抽象方法
public abstract void show();
}
// 定义第二个抽象父类
abstract class Fu2 {
public abstract void show();
}
// 定义一个子类继承抽象方法 (类与类不支持一个继承多个)
abstract class Zi extends Fu1, Fu2 { // 报错 同时继承了两个类
// 重写抽象方法
public void show() {
}
}
2、 类和接口之间的关系(这里展示一个继承多个的代码实现):
package com.liujintao.demo;
public class InterfaceDemo02 {
public static void main(String[] LiuJinTao) {
}
}
// 定义一个接口
interface Interf {
public void show ();
public void method();
}
// 定义第二个接口
interface Interf2 {
public void show ();
public void method ();
}
// 定义一个实现类(一个类继承多个接口(类))
abstract class testClass implements Interf, Interf2 {
// 实现了接口(就相当于继承了),里面全是抽象方法,因此必须存活在抽象类中。
public void show () {
System.out.println("我是实现类,实现接口继承方法后,重写抽象类");
}
public void method () {
System.out.println("我是实现类,实现了接口的继承方法后,重写抽象类");
}
}
- 这里主要看我实现类以及里面对抽象方法的重写。
3、 接口和接口之间的关系(和上面一样,一个接口继承多个接口代码展示):
package com.liujintao.demo;
public class InterfaceDemo02 {
public static void main(String[] LiuJinTao) {
}
}
// 定义第一个接口
interface isInter1 {
public void showA();
}
// 定义第二个接口
interface isInter2 {
public void showB();
}
// 定义第三个接口,实现上面连个接口的继承
interface Come extends isInter1, isInter2 {
public void showA();
public void showB();
}
- 一个接口使用继承的方式继承多个接口,如果下次有个实现类,就得重写这些接口里面的所有抽象方法。
3.4 接口和抽象类的对比
- 抽象类:对事物做抽象(描述事物)
- 接口:对行为抽象(制定规则)
接口里面写的全是抽象的方法,然后通过实现类对我的规则进行重写,完成功能的实现。
四、多态
4.1 多态的前提条件
- 有继承/接口实现关系
- 有方法重写
- 父类引用指向子类对象
多态分为:
- 对象多态
- 行为多态
4.2 对象多态
- 父类的引用指向了子类的对象
package com.liujintao.polymorphic;
public class PolymorphicDemo {
public static void main(String[] LiuJinTao){
// 对象多态的实现
Animal x = new Dog();
Animal y = new Cat();
}
}
// 定义一个父类
class Animal {
}
// 下面定义两个子类
class Dog extends Animal {
}
class Cat extends Animal {
}
对象多态的好处:
- 方法的形参定义为父类类型,这个方法就可以接受到该父类的任意子类对象了。
package com.liujintao.polymorphic;
public class PolymorphicDemo {
public static void main(String[] LiuJinTao){
// 对象多态的实现
Animal x = new Dog();
Animal y = new Cat();
// 调用方法 传递子类对象给父类引用
userAnimal(new Dog());
userAnimal(new Cat());
}
// 展示一下对象多态的好处 (就是定义一个父类的实例,接受子类对象)
public static void userAnimal (Animal element) {
}
}
// 定义一个父类
class Animal {
}
// 下面定义两个子类
class Dog extends Animal {
}
class Cat extends Animal {
}
4.2 行为多态:
package com.liujintao.polymorphic;
import java.sql.SQLOutput;
public class PolymorphicDemo {
public static void main(String[] LiuJinTao){
// 调用方法 传递子类对象给父类引用
// userAnimal(new Dog());
userAnimal(new Cat());
}
// 展示一下对象多态的好处 (就是定义一个父类的实例,接受子类对象)
public static void userAnimal (Animal element) {
// 行为多态的使用
element.eat(); // cat
}
}
// 定义一个父类
abstract class Animal {
public abstract void eat ();
}
// 下面定义两个子类
class Dog extends Animal {
public void eat () {
System.out.println("dog");
}
}
class Cat extends Animal {
public void eat () {
System.out.println("cat");
}
}
userAnimal(new Cat());
: 根据传递的子类对象,方法的形参引用不同的对象,实现功能方法。
4.3 多态的成员访问特点
-
成员变量:编译看左边(父类), 运行看左边(父类)
-
成员方法:编译看左边(父类), 运行看右边(子类)
- 在编译的时候,会检查父类中有没有这个方法:
- 没有:编译报错
- 有:编译通过,但是运行的时候,一定会执行子类的方法逻辑
- 因为担心父类的方法里面没有逻辑,是一个抽象方法。
- 在编译的时候,会检查父类中有没有这个方法:
-
多态创建对象,调用静态成员:
- 静态的成员,推荐类名进行调用
- 细节:静态的成员,可以使用对象名调用,但这是一种假象。
- 生成字节码文件后,会自动将对象名调用,改成类名调用(也就是会说执行的时候就已经是类名调用了)
- 1、访问成员变量的时候,访问的是父类,如果将变量设计在了本类,那就是本类的变量值。
package com.liujintao.polymorphic;
public class polymorphicDemo02 {
public static void main(String[] args) {
Zi z = new Zi();
System.out.println(z.num); // 100
}
}
// 定义一个父类
class Fu {
int num = 100;
public void method () {
System.out.println(num);
}
}
// 定义一个子类
class Zi extends Fu {
public void method () {
System.out.println(num);
}
}
- 2、访问成员方法的时候
package com.liujintao.polymorphic;
public class polymorphicDemo02 {
public static void main(String[] args) {
Zi z = new Zi();
System.out.println(z.num); // 100
z.method(); // 我是子类
}
}
// 定义一个父类
class Fu {
int num = 100;
public void method () {
System.out.println(num);
}
}
// 定义一个子类
class Zi extends Fu {
public void method () {
System.out.println(num);
System.out.println("我是子类");
}
}
- 3、访问的是父类
Zi z = new Zi();
Zi.print(); // <== z.print(); 编译的时候自动改为类调用。
// 定义一个父类
class Fu {
public static void print() {
System.out.println("父类----print");
}
}
// 定义一个子类
class Zi extends Fu {
public static void print() {
System.out.println("父类----print");
}
}
- 总而言之,多态的访问,必须符合多态的形式
- 父类没有的,子类有的就访问不了,(这就是多态的弊端),解决方法就得用转型技术。往下面看。
4.4 多态的转型技术
向上转型:
- 从子到父 (父类引用指向子类对象)
Fu f = new Zi();
向下转型:
- 从父到子(将父类引用所指向的对象,转交给子类类型)
Zi z = (Zi)f;
4.5 多态中的转型问题
- 关键字 instanceof
- 使用格式:
- 对象名 instanceof 类型
- 判断一个对象是否是一个类的实例
- (通俗易懂的理解:判断关键字左边的对象,是否是右边的类型,返回值为boolean类型)就是判断数据类型是否相同
五、综合练习:
测试类:
package com.liujintao.test;
import com.liujintao.polymorphic.PolymorphicDemo03;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请选择支付方式: 1. 支付平台支付 2. 银行卡网银支付 3. 信用卡快捷支付");
int choice = sc.nextInt();
// 定义一个接口类型的引用
Payment payment = null;
switch (choice) {
case 1 :
// 父类引用指向子类对象
payment = new PlatformPaymentImpl();
break;
case 2:
payment = new BankcardPaymentImpl();
break;
case 3:
payment = new CreditCardsAccepted();
}
System.out.println("请输入您的支付金额: ");
double money = sc.nextDouble();
// 通过实现类对象。访问实现类里面的方法
payment.pay(money);
}
}
先定义一个接口:
package com.liujintao.test;
/**
* 支付接口
*/
public interface Payment {
void pay(double money);
}
第一个实现类:
package com.liujintao.test;
/**
* 实现类
*/
public class PlatformPaymentImpl implements Payment {
/**
* 重写接口方法
* @param money
*/
@Override
public void pay(double money) {
System.out.println("通过支付平台支付了:" + money + "元!");
}
}
第二个实现类:
package com.liujintao.test;
/**
* 实现类
*/
public class BankcardPaymentImpl implements Payment{
@Override
public void pay(double money) {
System.out.println("通过银行卡网银支付了:" + money + "元!");
}
}
第三个实现类:
package com.liujintao.test;
/**
* 实现类
*/
public class CreditCardsAccepted implements Payment {
public void pay(double money) {
System.out.println("通过信用卡支付了:" + money + "元");
}
}