多态
多态:同一个引用类型,使用不同的实例而执行不同操作
多态性是OOP中的一个重要特性,主要是用来实现动态联编的,换句话说,就是程序的最终状态只有在执行过程中才被决定而非在编译期间就决定了。这对于大型系统来说能提高系统的灵活性和扩展性。
类型转换
向上转型——子类转换为父类,自动进行类型转换
向下转型——父类转换为子类,结合instanceof运算符进行强制类型转换
实现多态的两种方式
使用父类作为方法形参实现多态
使用父类作为方法返回值实现多态
使用多态的好处
多态可以减少类中代码量,可以提高代码的可扩展性和可维护性
引用变量的两种类型
编译时类型(模糊一点,一般是一个父类)由声明时的类型决定。
运行时类型(运行时,具体是哪个子类就是哪个子类)由实际对应的对象类型决定。
多态的存在要有3个必要条件:
要有继承,要有方法重写,父类引用指向子类对象
package petrel.com;
public abstract class Pet {
public abstract void feed();
}
------------
package petrel.com;
public class Dog extends Pet{
@Override
public void feed() {
System.out.println("狗狗在吃骨头");
}
}
------------
package petrel.com;
public class Cat extends Pet {
@Override
public void feed() {
System.out.println("猫在吃鱼");
}
}
------------
package petrel.com;
public class Penguin extends Pet {
@Override
public void feed() {
System.out.println("企鹅在吃");
}
}
------------
package petrel.com;
/**
* 多态:
* 对应同一个指令(调用同一个名称的方法),不同的对象给予不同的反应(不同的方法实现)
* 规范(多态实现的提前):
* 1、必须要有继承关系
* 2、子类方法必须重写父类的方法(狗吃骨头,猫吃鱼)(好像是说如果没有重写就是调用了父类的同一方法,这样就不是多态)
* 3、父类引用指向子类对象(自动类型转换:Dog dog = new Dog();等于Pet dog = new Dog();)
*
* 多态的目的:
* 为了提高代码的扩展性和维护性
* 方便代码逻辑的编写
* 多态的两种表现形式:
* 1、父类作为方法的参数
* 2、父类作为方法的返回值类型
*
* 引用类型的转换跟基本数据类型的转换类似:
* 1、当父类需要转成子类的时候,要进行强制转换,但是在强制转换之前一定要先判断父类引用指向的子类对象到底是谁,
* 如果无法确定,在运行过程中可能出错
* 用instanceof运算符判断
* 2、当子类需要向父类转换的时候,直接自动转换,不需要进行任何的判断。
*
*
*/
public class Person {
//创建两个feed 一个猫的 一个狗的。方法的重载
public void feed(Cat cat){
cat.feed();
}
public void feed(Dog dog){
dog.feed();
}
//合并上面两个方法, 这样就可以称之为多态,是猫是狗不知道,参数调用进去后才知道
public void feed(Pet pet){
pet.feed();
}
public Pet buyPet(int type){
if(type == 1){
return new Dog();
}else if (type == 2){
return new Cat();
}else {
return new Penguin();
}
}
public static void main(String[] args) {
Person p = new Person();
Dog dog = new Dog();
Cat cat = new Cat();
Pet penguin = new Penguin();
p.feed(dog);
p.feed(cat);
p.feed(penguin);
Pet pet = p.buyPet(1);
if(pet instanceof Dog){
System.out.println("买的是一只狗");
}else if(pet instanceof Cat){
System.out.println("买的是一只猫");
}else{
System.out.println("买的是一只企鹅");
}
}
}
接口 interface
接口表示一种能力
接口表示一种约定
接口特性
– 接口不可以被实例化
– 实现类必须实现接口的所有方法
– 实现类可以实现多个接口
– 接口中的变量都是静态常量
为什么需要接口?接口和抽象类的区别?
– 接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类迚行约束。 全面地专业地实现了:规范和具体实现的分离。
– 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须 能…”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你好人,则必须干掉坏人;如果你是坏人,则必须欺负好人。
– 接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
– 项目的具体需求是多变的,我们必须以不变应万变才能从容开发,此处的 “不变”就是“规范”。因此,开发项目往往都是面向接口编程!
接口相关规则
– 接口中所有方法都是抽象的。
– 即使没有显式的将接口中的成员用public标示,也是public访问类型的
– 接口中变量默认用 public static final标示,所以接口中定义的变量就是全局静态常量。
– 可以定义一个新接口,用extends去继承一个已有的接口
– 可以定义一个类,用implements去实现一个接口中所有方法。
– 可以定义一个抽象类,用implements去实现一个接口中部分方法。
注意:extends 必须位于implements之前
package petrel.com.interfacedemo;
public abstract class Door {
public abstract void openDoor();
public abstract void closeDoor();
}
------------
package petrel.com.interfacedemo;
public interface Lock {
void openLock();
void closeLock();
}
------------
package petrel.com.interfacedemo;
public class LockDoor extends Door implements Lock{
@Override
public void openDoor() {
System.out.println("开门");
}
@Override
public void closeDoor() {
System.out.println("关门");
}
@Override
public void openLock() {
System.out.println("开锁");
}
@Override
public void closeLock() {
System.out.println("关锁");
}
}
------------
package petrel.com.interfacedemo;
/**
* java中的继承关系是单继承,如果拥有多个父类的时候,可以考虑使用接口进行实现
*
* 用法:
* 使用interface来修饰
* 接口中可以包含多个方法,且方法跟抽象类中的抽象方法一致,可以不写实现,子类在实现的时候必须要实现代码逻辑
* 子类实现接口使用implements关键字
*
* 特征:
* 1、接口中的所有方法都是抽象方法,不能包含方法的实现
* void openLock(){ }; 这样会报错
* 2、接口中的所有方法的访问修饰权限都是public,不写并不是默认访问权限,而是public
* protected void openLock(); 这样会报错
* 3、接口不能被实例化
* Lock lock = new Lock(); 这样会报错
* 4、接口的子类必须要实现接口中的所有方法,跟抽象类有所不同,抽象类中的抽象方法必须要被子类实现
*
* 5、子类可以拥有实现多个接口
* public class LockDoor extends Door implements Lock.*.*{}
* 6、接口中的变量都是静态常量,如果变量没有使用static关键字修饰,它也表示静态常量,不用final关键字修饰,也是常量
* int a = 10;
* 可以这样:LockDoor.a
* 即使没有final关键字修饰 a也不能修改
* 定义的时候编译器会自动把static final加上
* 7、接口中的方法和常量无论是否添加public修饰,默认的权限有且仅有一个,就是public
*
** 抽象类和接口的区别:
* * 1、抽象类中的方法可以有抽象方法,也可以有普通方法,但是接口中只能包含抽象方法
* * 2、抽象类需要使用abstract关键字来修饰,而接口使用interface关键字来修饰
* * 3、子类使用extends关键字来继承抽象类,使用implements来实现接口
* * 4、子类继承抽象类的时候必须要实现所有的抽象方法,普通方法可以不重写,而接口中的所有方法必须实现
* * 5、抽象类中可以定义成员变量,而接口中只能定义静态常量
* * 6、抽象类在子类实现的时候是单继承,而接口是多继承
* * 7、抽象类和接口都不能实例化,但是抽象类中可以有构造方法,而接口中不能有构造方法
* * 8、抽象类中可以实现接口,并且不实现接口中方法,而接口只能继承接口,不能实现接口
* * 注意:
* * 在实际的项目开发过程中,如果可以使用接口,尽量使用接口,将单继承的父类留在最关键的地方
*/
public class TestLockDoor {
public static void main(String[] args) {
LockDoor lockDoor = new LockDoor();
lockDoor.openDoor();
lockDoor.openLock();
lockDoor.closeDoor();
lockDoor.closeLock();
}
}
package petrel.com.interfacedemo2;
public interface Usb {
public void dataTransfer();
}
------------
package petrel.com.interfacedemo2;
public class Mouse implements Usb{
@Override
public void dataTransfer() {
System.out.println("鼠标来点击屏幕");
}
}
------------
package petrel.com.interfacedemo2;
public class Upam implements Usb {
@Override
public void dataTransfer() {
System.out.println("upan可以传输数据");
}
}
------------
package petrel.com.interfacedemo2;
/**
* 接口的使用:
* 1、接口代表一种能力,接口中可以定义N多个方法,子类在进行实现的时候,必须要实现这些方法
* (接口只要定义了能力 子类就要实现)
* 将这些方法进行实现,就意味着具体了方法的能力
* 关心实现类有何能力,而不关心实现细节
*
*/
public class Test {
public static void main(String[] args) {
Mouse mouse = new Mouse();
mouse.dataTransfer();
Upam up = new Upam();
up.dataTransfer();
}
}
package petrel.com.interfacedemo3;
public interface InkBox {
public void getWriteAndBlock();
public void getColor();
}
------------
package petrel.com.interfacedemo3;
public interface Paper {
public void getA4();
public void getB5();
}
------------
package petrel.com.interfacedemo3;
public class CopyMechine implements InkBox,Paper{
@Override
public void getWriteAndBlock() {
System.out.println("使用黑白墨盒打印");
}
@Override
public void getColor() {
System.out.println("使用彩色墨盒打印");
}
@Override
public void getA4() {
System.out.println("使用A4纸打印");
}
@Override
public void getB5() {
System.out.println("使用B5纸打印");
}
public static void main(String[] args) {
CopyMechine copyMechine = new CopyMechine();
copyMechine.getWriteAndBlock();
copyMechine.getA4();
}
}
package petrel.com.interfacedemo3;
public interface InterfaceDemo {
/*
* 此方法表示可以实现展示A的功能
* 参数要求,必须是整型和String类型
*
* 程序设计时面向接口的约定而不考虑具体实现
* */
public void A(int a,String b);
}
------------
package petrel.com.interfacedemo3;
public class InterfaceImpl implements InterfaceDemo {
@Override
public void A(int a, String b) {
}
}
package petrel.com.interfacedemo4;
public interface CPU {
//public static final String str = "hehe";
public String getBrand();
public String getHZ();
}
------------
package petrel.com.interfacedemo4;
public class AmdCpu implements CPU{
@Override
public String getBrand() {
return "amd";
}
@Override
public String getHZ() {
return "1000";
}
}
----------
package petrel.com.interfacedemo4;
public class InterCpu implements CPU {
@Override
public String getBrand() {
return "inter";
}
@Override
public String getHZ() {
return "2000";
}
}
------------
package petrel.com.interfacedemo4;
public interface HardDisk {
public String getVolumn();
}
------------
package petrel.com.interfacedemo4;
public class JSDHardDisk implements HardDisk{
@Override
public String getVolumn() {
return "金士顿";
}
}
------------
package petrel.com.interfacedemo4;
public class SXHardDisk implements HardDisk {
@Override
public String getVolumn() {
return "三星";
}
}
------------
package petrel.com.interfacedemo4;
public class Computer {
public void show(CPU cpu,HardDisk hardDisk){
System.out.println("计算机的组成如下:");
System.out.println("cpu:"+cpu.getBrand()+" ,主频是:"+cpu.getHZ());
System.out.println("硬盘容量是:"+hardDisk.getVolumn());
}
}
------------
package petrel.com.interfacedemo4;
public interface Memory {
public String getCapacity();
}
------------
package petrel.com.interfacedemo4;
public class Test {
public static void main(String[] args) {
Computer computer = new Computer();
CPU cpu = new InterCpu();
HardDisk hardDisk = new JSDHardDisk();
computer.show(cpu,hardDisk);
}
}
/*
运行结果:
计算机的组成如下:
cpu:inter ,主频是:2000
硬盘容量是:金士顿
*/
package petrel.com.interfacedemo5;
public interface A {
public void show();
}
------------
package petrel.com.interfacedemo5;
/**
* 可以定义一个新接口,用extends去继承一个已有的接口
* public interface B extends A
*/
public interface B extends A{
}
------------
package petrel.com.interfacedemo5;
/**
* 定义抽象类,方法可以重写,也可以不重写
*/
public abstract class C implements A{
}
内部类
把一个类定义在另一个类的内部
注意事项:
(1)外部类不能直接使用内部类的成员和方法
(2)如果外部类和内部类具有相同的成员变量戒方法,内部类
默认访问自己的成员变量或方法,如果要访问外部类的成员变量
需使用this关键字
将一个类定义置入另一个类定义中就叫作“内部类”
类中定义的内部类特点
Ø 内部类作为外部类的成员,可以直接访问外部类的成员(包括private成员),反之则不行。
Ø 内部类做为外部类成员,可声明为private、默认、protected或public。
Ø 内部类成员只有在内部类的范围之内是有效的。
Ø 用内部类定义在外部类中不可访问的属性。这样就在外部类中实现了比外部类的private还要小 的访问权限。
– 编译后生成两个类: OuterClass.class 和OuterClass$InnerClass.class
▪ 内部类分类 – 成员内部类 静态内部类 方法内部类 匿名内部类
匿名内部类Anonymous
– 可以实现一个接口,戒者继承一个父类
– 只能实现一个接口
– 适合创建那种只需要一次使用的类,不能重复使用。比较常见的是在图形界面编程GUI里用得到。
– 匿名内部类要使用外部类的局部变量,必须使用final修饰该局部变量
package petrel.com.innerdemo;
public class InnerClassDemo {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("show");
//System.out.println(age); 这里会报错 因为age是内部类的私有属性 外部类不能访问
InnerClass inner = new InnerClass();
System.out.println(inner.age);//通过new了一个对象访问私有属性
}
class InnerClass{
private int age;
//static int no; 这里会报错 因为内部类中不能定义静态属性
public void test(){
System.out.println("test");
System.out.println(id);//内部类可以方便的访问外部类的私有属性
}
//内部类的内部类
class InnerInner{
private int id;
public void print(){
System.out.println("print");
}
}
}
public static void main(String[] args) {
InnerClass innerClass = new InnerClassDemo().new InnerClass();
}
}
------------
package petrel.com.innerdemo;
/**
* @author Petrel
* @data 2020/6/19 20:19
*/
/**
* 内部类(当作类中的一个普通成员变量,只不过此成员变量是class的类型):
* 一个java文件中可以包含多个class,但是只能有一个public class
* 如果一个类定义在另一个类的内部,此时可以称之为内部类
*
* 使用:
* 创建内部类的时候,跟之前的方法不一样,需要在内部类的前面添加外部类来进行修饰
* InnerClassDemo.InnerClass inner = new InnerClassDemo().new InnerClass();
*
* 特点:
* 1、内部类可以方便的访问外部类的私有属性
* 2、外部类不能直接访问内部类的私有属性,但是如果创建了内部类的对象,此时可以在外部类中访问私有属性
* 3、内部类中不能定义静态属性
* 4、当内部类和外部类具有相同的私有属性的时候,在内部类中访问的时候,可以直接访问内部类的属性,
* 如果需要访问外部类的属性,那么需要添加 外部类类名.this.属性。
*
* 分类:
* 匿名内部类:当定义了一个类,实现了某个接口的时候,在使用过程中只需要使用一次,没有其他用途
* 其实考虑到代码编写的简洁,可以考虑不创建具体的类,而采用new interface(){添加未实现的方法}
* 就叫做匿名内部类
* 静态内部类:在内部类中可以定义静态内部类,使用static关键字进行修饰,使用规则
* 外部类.内部类 类的引用名称 = new 外部类.内部类();
* 方法内部类:在外部类的方法中也可以定义类,此时叫做方法内部类(了解即可)
* 使用的时候需要注意,只能在方法中创建对象,因为此class的作用域就是当前方法
* public void show(){
* System.out.println("show");
*
* class InnerClass{
* private String name;
* public void test(){
* System.out.println("test");
* }
* }
* } 将class InnerClass这个方法定义到public void show(){这个show方法里面了
*/
public class TestInnerClass {
public static void main(String[] args) {
InnerClassDemo innerClassDemo = new InnerClassDemo();
innerClassDemo.show();
System.out.println(innerClassDemo.getName());
//定义InnerClass时会自动加上InnerClassDemo.
//InnerClassDemo.InnerClass inner = new InnerClassDemo.InnerClass; 即使加上了InnerClassDemo. 这样也是错误的
//要这样 写两个new 先把外部的对象创建好 再创建里面的内部类
InnerClassDemo.InnerClass inner = new InnerClassDemo().new InnerClass();
inner.test();
//内部类的内部类new对象
InnerClassDemo.InnerClass.InnerInner innerInner = new InnerClassDemo().new InnerClass().new InnerInner();
}
}
package petrel.com.innerdemo2;
/**
* @author Petrel
* @data 2020/6/19 20:54
*/
public class Outer {
private String name = "张三";
class Inner{
private String name = "Lisi";
public void show(){
System.out.println(name);
System.out.println(this.name);
System.out.println(Outer.this.name); //标识外部类里面的属性
}
}
public static void main(String[] args) {
Outer.Inner inner = new Outer().new Inner();
inner.show();
}
}
package petrel.com.innerdemo2;
/**
* @author Petrel
* @data 2020/6/19 21:19
*/
public class NoNameInnerClassDemo {
public static void main(String[] args) {
//匿名内部类,只要用到一次 为了简洁而采用new interface(){添加未实现的方法} 也就是new Runnable()
new Thread(new Runnable() {
@Override
public void run() {
}
});
}
}
package petrel.com.innerdemo2;
/**
* @author Petrel
* @data 2020/6/19 21:35
*/
public class StaticClass {
private int id;
public void test(){
System.out.println("test");
}
static class InnerClass{
private String name;
public void show(){
System.out.println("show");
}
}
public static void main(String[] args) {
InnerClass innerClass = new StaticClass.InnerClass();
}
}
package petrel.com.innerdemo2;
/**
* @author Petrel
* @data 2020/6/20 8:49
*/
public class MethodInnerClass {
public void show(){
System.out.println("show");
class InnerClass{
private String name;
public void test(){
System.out.println("test");
}
}
//使用的时候需要注意,只能在方法中创建对象
new InnerClass().test();
}
public static void main(String[] args) {
MethodInnerClass methodInnerClass = new MethodInnerClass();
methodInnerClass.show();
}
}