8.7 多态
什么是多态? 即同一方法可以根据发送对象的不同而采用多种不同的方式。
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多。在句话我是这样理解的:
在实例中使用方法都是根据他最开始将类实例化最左边的类型来定的,但是父类引用指向对象子类的话,如果子类有重写的方法(即方法名与父类相同的方法但是内容不一定相同),那么执行的子类所重写的方法,如果没有重写的方法,就执行父类的。在这句话中所说的"但可以指向对象的引用的类型有很多",意思是一个父类可以有很多的子类,都可以使用他们的重写方法。
示例:
父类Person:
java
package com.oop.demo06;
public class Person {
public void run(){
System.out.println("run");
}
}
子类Student:
java
package com.oop.demo06;
public class Student extends Person {
@Override
public void run() {
System.out.println("son");
}
public void eat(){
System.out.println("eat");
}
}
测试类:
java
import com.oop.demo06.Student;
import com.oop.demo06.Person;
public class AppLication{
public static void main(String[] args) {
// 一个对象的实际类型是确定的
// 可以指向的引用类型就不确定了:父类的引用指向子类
// Student 能调用的方法都是自己的或者继承父类的!
Student S1 = new Student();
// Person是父类型的类,可以指向子类,但是不能调用子类独有的方法
Person S2 = new Student();
Object S3 = new Student();
S2.run(); // 子类重写了父类的方法,执行子类的方法
S1.run();
// 对象能执行能执行哪些方法,主要看对象的左边类型,和右边关系不大!
((Student) S2).eat(); //将S2的类型强制转换为Student,就可以调用方法了!
S1.eat();
}
}
/*
多态注意事项:
1. 多态是方法的多态,属性没有多态
2. 父类和子类要有联系 类型转换异常! ClassCastException!
3. 存在条件: 继承关系,方法需要重写,父类引用指向子类对象!
1. static 方法,属于类,它不属于实例
2. final 常量;
3. private 方法
*/
8.8 instanceof 和 类型转换
instanceof 使用的方法格式:
【实例的名称 instanceof 类的类型名称】,判断一个对象是什么类型,就是判读两个类型的对象是否有父子关系,有的话就返回Ture,没有就是返回False。
使用 【实例的名称 instanceof 类的类型名称】时,能否编译看的是实例化对象的类型名,输出的结果看的是实例化对象时最右边的所实例的对象值。
首先父类是Person,其余的类:Student、Teacher是Person的子类。
java
import com.oop.demo06.Student;
import com.oop.demo06.Person;
import com.oop.demo06.Teacher;
public class AppLication{
public static void main(String[] args) {
// Object > Person > Student
// Object > Person > Tercher
// Object > String
Object object = new Student();
System.out.println(object instanceof Student); // true
System.out.println(object instanceof Person); // true
System.out.println(object instanceof Object); // true
System.out.println(object instanceof Teacher); // false
System.out.println(object instanceof String); // false
System.out.println("=====================================");
Person person = new Student();
System.out.println(person instanceof Student); // true
System.out.println(person instanceof Person); // true
System.out.println(person instanceof Object); // true
System.out.println(person instanceof Teacher); // false
// System.out.println(person instanceof String); // 编译时就报错了
System.out.println("=====================================");
Student student = new Student();
System.out.println(student instanceof Student); // true
System.out.println(student instanceof Person); // true
System.out.println(student instanceof Object); // true
// System.out.println(student instanceof Teacher); // 编译时就报错
// System.out.println(student instanceof String); // 编译时就报错
}
}
类型转换(关于对象的类型):
java
import com.oop.demo06.Student;
import com.oop.demo06.Person;
import com.oop.demo06.Teacher;
public class AppLication{
public static void main(String[] args) {
// 类型之间的转化: 父 子
// 高 低
Person student = new Student();
// student 将这个对象转换为Student的对象类型
// 我们就可以使用这个对象类型中的方法了
((Student) student).go(); // 这个是高转低需要强制转换
// 如果是低转高,子类转换为父类不需要强制转换,可能会丢失一些方法!
Student student1 = new Student();
Person person = student1;
}
}
8.9 static 关键字详解
static修饰符有着静态的意思,使用他代表着这个方法或者元素在类中是与类一起加载的。
java
package com.oop.demo07;
// static
public class Student {
private static int age; // 静态变量 多线程
private double score; // 非静态变量
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(s1.score);
System.out.println(age);
}
}
在类中,还有着代码块这种东西,他的优先级比这个构造器还高。
java
package com.oop.demo07;
public class Person {
// {
// // 代码块(匿名代码块)
// }
//
// static {
// // 静态代码块
// }
// 第二个执行,可以用来赋初始值
{
System.out.println("匿名代码块");
}
// 第一个执行,与类一起加载,只执行一次,不管你实例化多少个对象
static {
System.out.println("静态代码块");
}
// 第三个执行,构造器
public Person(){
System.out.println("构造方法");
}
public static void main(String[] args) {
Person person = new Person();
System.out.println("==============");
Person person1 = new Person();
}
}
在Java中有许许多多的有用又有趣的类,在这些类中有着许多有用的静态方法,可以使用下面这个方法直接调用,想查看类的调用位置直接ctrl+左键就行。
java
package com.oop.demo07;
// 导入其他包中的类的静态方法
import static java.lang.Math.random; // 返回一个随机数(0,1)
import static java.lang.Math.PI; // 圆周率
public class Test {
public static void main(String[] args) {
System.out.println(random());
System.out.println(PI);
}
}
需要注意的是:
如果给这些东西使用了常量修饰符final,那么他将会是唯一的,无无法拥有子类。
8.10 抽象类
什么是抽象类?abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么就是抽象类。
抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。
抽象类,不能用new关键字来创建对象,它是用来让子类继承的。
抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。
子类继承了抽象类,那么他就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。
抽象父类:
java
package com.oop.demo08;
//abstract 抽象类:类
public abstract class Action {
// 约束~有人帮我们实现~
// 这个就是抽象的方法,我们只定义了方法名字,他的具体功能由别人实现
public abstract void doSomething();
// 1. 不能new这个抽象类,只能靠子类去实现它;约束!
// 2. 抽象类中可以写普通的方法
// 3. 抽象方法必须在抽象类中
// 抽象的抽象:约束~
}
抽象父类的子类,他里面有重写父类的方法:
java
package com.oop.demo08;
// 抽象类的所有方法,继承了他的子类,都必须要实现他的方法
public class A extends Action {
@Override
public void doSomething() {
}
}
8.11 接口的定义与实现
接口的作用:
1. 约束
2. 定义一些方法,让不同的人实现
3. public abstract
4. public static final
5. 接口不能实例化,接口中没有构造方法
6. implements可以实现多个接口
7. 必须要重写接口中的方法
接口UserService:
java
package com.oop.demo09;
//interface 定义接口的修饰符(关键字),接口都需要有实现类
public interface UserService {
// 接口中定义就是常量 public static final
int AGE = 9999;
// 接口中的所有定义的方法其实都是抽象的 public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
接口TimeService:
java
package com.oop.demo09;
public interface TimeService {
void timer();
}
每个接口都需要有实现类。我是这样理解的,每个接口就是定义一堆方法的名字与类型就是没有里面的内容,而他们需要有实现类来实现里面的内容,需要用到关键字implements:
java
package com.oop.demo09;
// 类 可以实现接口 implements 接口
// 实现了接口的类,就需要重新接口中的方法
// 利用接口实现多继承
public class UersServiceImpl implements UserService,TimeService{
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
}
}
8.12 N种内部类
java
package com.oop.demo10;
public class Outer {
private int id = 14203;
public void out(){
System.out.println("这是外部类的方法");
}
public class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
// 内部类能够获得外部类的私有属性
public void getID(){
System.out.println(id);
}
}
}
java
import com.oop.demo10.Outer;
import java.util.Optional;
public class AppLication{
public static void main(String[] args) {
Outer outer = new Outer();
// 通过这个外部类来实例化内部类
Outer.Inner inner = outer.new Inner();
inner.in();
inner.getID();
}
}
局部内部类:
java
package com.oop.demo10;
public class Outer {
// 局部内部类,在方法里的属性也叫做局部变量
public void method(){
class Inner{
}
}
}
匿名内部类:
java
package com.oop.demo10;
public class Test {
public static void main(String[] args) {
// 没有名字初始化类,匿名类
// 不用将实例保存在对象中
new Apple();
new Apple().eat();
// 甚至可以匿名一个接口
new Userservice(){
@Override
public void happle() {
}
};
}
}
class Apple{
public void eat(){
System.out.println("eat");
}
}
interface Userservice{
void happle();
}