面向对象编程
多态
什么是多态
- 动态编译:类型:可扩展性
- 即同一方法可以根据发送对象的不同而采用多种不同的行为方式
- 一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多
- 多态存在的条件
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
- 多态是方法的多态,属性没有多态性
- instanceof 和 类型转换
多态样例
//父类
public class Person {
public void run(){
System.out.println("father");
}
public void fatherSay(){
System.out.println("father told son to study");
}
}
//子类
public class Student extends Person {
@Override
public void run() {
System.out.println("son");
}
public void eat(){
System.out.println("son is eating");
}
}
//主方法调用
public class Application {
public static void main(String[] args) {
//指向的引用类型不确定,可以是指向实际类型,可以是父类指向子类,可以是Obejct指向实际类型
//对象的实际类型是确定的(new Student();)
Student s1 = new Student(); //子类指向引用子类
Person s2 = new Student(); //父类指向引用子类,子类不能指向父类
Object s3 = new Student();
//单独运行父类方法,结果:father
// s2.run();
//运行父类方法后,运行子类中的方法,子类将父类的方法重写了,结果:son son
// s2.run();
// s1.run();
//子类可正常调用子类中的方法,结果:son is eating
// s1.eat();
//父类无法直接调用子类中的方法,报错
// s2.eat();
//子类可以继承并调用哦父类的方法,结果:father told son to study
// s1.fatherSay();
}
}
instanceof关键字
作用
- instanceof 是 Java 的一个二元操作,符等 ==,>,< 操作符。
- instanceof 是 Java 的保留关键字。它的作用是测试它映射的对象是否是它正确的类的实例,返回布尔值的数据类型。
判断Object类与子类、其他类的关系
//多态的类型判断,通过instanceof判断测试它映射的对象是否是它正确的类的实例
public class Application {
public static void main(String[] args) {
Object object = new Student();
//通过instanceof关键字判断类型是否相同
//Object>Person>Student ----父类子类继承关系,object指向了Student,所以类型相同
//Object>Person>Teacher ----Teacher有继承关系,但父类没有指向Teacher,所以类型不同
//Object>String ----不在同一个包下,没有任何关系,多以类型不同
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
}
}
判断Person类与子类、父类、其他类的关系
//多态的类型判断,通过instanceof判断测试它映射的对象是否是它正确的类的实例
public class Application {
public static void main(String[] args) {
Person person = new Student();
//通过instanceof关键字判断类型是否相同
//Object>Person>Student ----父类子类继承关系,object指向了Student,所以类型相同
//Object>Person>Teacher ----Teacher有继承关系,但父类没有指向Teacher,所以类型不同
//Object>String ----不在同一个包下,没有任何关系,多以类型不同
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); //编译就报错,Person和String都是属于Object底下的类,没有父子关系,无法进行比较
}
}
判断Student类与子类、父类、其他类的关系
//多态的类型判断,通过instanceof判断测试它映射的对象是否是它正确的类的实例
public class Application {
public static void main(String[] args) {
Student student = new Student();
//通过instanceof关键字判断类型是否相同
//Object>Person>Student ----父类子类继承关系,object指向了Student,所以类型相同
//Object>Person>Teacher ----Teacher有继承关系,但父类没有指向Teacher,所以类型不同
//Object>String ----不在同一个包下,没有任何关系,多以类型不同
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); //编译就报错,Student属于Object下Person下的类,Teacher属于Object下Person下的类,没有父子关系,无法进行比较
// System.out.println(person instanceof String); //编译就报错,Student属于Object下Person下的类,String属于Object下的类,没有父子关系,无法进行比较
}
}
instanceof 小结
- 父类中有,子类中没有,父类实体类使用时调用自身的方法
- 父类中有,子类中没有,子类会继承父类中的方法
- 父类中有,子类中也有,父类实体类使用时调用自身的方法
- 父类中有,子类中也有,子类实体类使用时会按照子类中的方法*重写父类的方法
- 父类中没有,子类中有,父类无法调用子类中的方法,子类可调用自身的方法
注意事项
- 多态是方法的多态,属性么有多态
- 父类和子类,类型相同,否则类型转换异常(ClassCastException)
- 多态存在条件:继承关系,方法需要重写,父类的引用指向子类对象
- 无法使用多态的情况
- static 方法,属于类,不属于实例,无法重写
- final 常量,无法重写
- private 私有方法,无法重写
类型转换
代码样例
//子类
public class Student extends Person {
public void go(){
System.out.println("go");
}
}
//父类
public class Person {
public void run(){
System.out.println("father");
}
}
//方法体
public class Application {
public static void main(String[] args) {
//对应的类型
Student s1 = new Student();
Person p1 = new Person();
//类之间强制转化:父 子
//子类型转化为父类型,父类型指向子类型
//高类型 <---- 低类型
Person obj = new Student(); //1.默认转换
Person p2 = s1; //1.默认转换
// p2.go(); //子类转换为父类,可能会丢失子类中的方法
//obj.go(); //编译报错,父类无法调用子类中的方法
//父类型转化为子类型,子类型指向父类型需要强制转化
//可以通过将父类强制转化为子类,然后调用子类中的方法
//低类型 <---- 高类型
Student student = (Student) obj;
student.go(); //go
}
}
类型转换 小结
- 父类引用指向子类的对象
- 把子类转换为父类,向上转型
- 把父类转换为子类,乡下转型,强制转换
- 方便方法的调用,减少重复的代码
抽象三大特性:封装、继承、多态!
static关键字
static关键字定义的属性和方法为静态的,可以在方法里直接调用
非静态属性和方法,需要通过new关键字来调用
public class Student {
private static int age; //静态的变量 多线程使用
private double score;//非静态的变量
public void run(){
go(); //非静态方法可以调用静态方法
}
public static void went(){
}
public static void go(){
//静态方法里可以调用静态方法,无法调用动态方法,可以调用goto(),无法调用run()
//类加载时已加载静态方法,类加载后加载非静态方法
}
public static void main(String[] args) {
Student sl = new Student();
System.out.println(Student.age); //静态变量可以直接调用
// System.out.println(Student.score); //无法从静态上下文中引用非静态 变量 score
System.out.println(sl.age);
System.out.println(sl.score);
new Student().run(); //通过new调用里面的run()方法,无法直接调用类里的非静态方法
Student.go(); //直接调用当前类中的go()方法
}
}
代码块的运行在构造器之前,静态代码块只有第一次加载的时候生成,非静态代码块每次类加载的时候都会重新加载
public class Person {
//执行顺序2:赋值初始值
{
//代码块(匿名代码块)
System.out.println("匿名代码块");
}
//执行顺序1:只执行一次
static {
//静态代码块
System.out.println("静态代码块");
}
//执行顺序3
public Person(){
System.out.println("构造方法");
}
public static void main(String[] args) {
//第一次执行
Person person1 = new Person();
System.out.println("====================================");
//第二次执行
Person person2 = new Person();
}
}
结果:
静态代码块
匿名代码块
构造方法
====================================
匿名代码块
构造方法
静态包导入
//静态导入包,导入后可直接通过方法名调用对应的方法
//import java.lang.Math.random; //报错,无法直接导入包内方法,需要使用static关键字
import static java.lang.Math.random;
public class Test {
public static void main(String[] args) {
//不导入包,直接调用随机数方法
System.out.println(Math.random());
//静态导入包后直接调用随机数方法
System.out.println(random());
}
//Math中存在final关键字,被final定义的方法无法继承,没有子类
//People继承Person类
public final class People extends Person{
}
//因People类使用了关键字final,所以其他类无法继承
// public class one extends People{
// }
}
抽象类
抽象类特点:
- 单继承
- 可以有普通方法和抽象方法
- 通过子类去实现功能
//abstract 抽象类
//类继承 extends 单继承,java内的类没有多继承。但是接口可以多继承
public abstract class Action {
//约束
//abstract,抽象方法,只有方法名字,没有方法的实现!
public abstract void doSomeThing();
//1. 不能new这个抽象类,只能靠子类去实现它:约束 //无法 new Action();
//2. 抽象类中可以有抽象方法,也可以有非抽象方法;非抽象类中不能有抽象方法(抽象方法必须存在抽象类中)
public void hello(){
System.out.println("非抽象方法hello();");
}
//抽象类不能 new ,但是内部存在构造器
//抽象类存在的意义,节省代码空间,提高开发效率
}
接口
接口和抽象类的区别
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有(使用abstract定义类)
接口:只有规范,自己无法些方法,约束和实现分离:面向接口编程(通过interface定义接口类,通过implements继承接口定义实现类)
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是……则必须能……”的思想
接口的本质是契约,制定好以后都要遵守
OO(面向对象)的精髓,是对对象的抽象,最能体现这一点的就是接口。
为什么我们讨论设计,模式都只针对具备了抽象能力的语言(比如c++、java、c#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。
声明类的关键字是class,声明接口的关键字是interface
接口实例
定义接口UserService
//锻炼抽象的思维
//接口定义关键字 interface
public interface UserService {
//接口里不能写方法
// public void run(){
// }
//常量,接口里不建议使用
int age = 99; //public static final int age = 99;
//接口中的所有定义的方法其实都是抽象的 public abstract,可以不写
//返回类型 方法名(参数)
void add(String name);
void del(String name);
void update(String name);
void query(String name);
}
定义接口Timer
public interface TimeService {
void timer();
}
通过类实现接口中的方法
// 类 可以实现接口 implements 接口
// 实现了接口的类,就需要重写接口中的方法
// 多继承 (implements UserService,TimeService 继承了两个接口)
public class UserServiceImpl implements UserService,TimeService {
//需要重写,全部继承的所有接口类中的方法,否则报错
@Override
public void add(String name) { //方法体 }
@Override
public void del(String name) { //方法体 }
@Override
public void update(String name) { //方法体 }
@Override
public void query(String name) { //方法体 }
@Override
public void timer() { //方法体 }
}
接口的作用
- 约束,没有具体的实现
- 定义一些方法,让不同的人实现,可以通过接口调用方法,不同的实现
- 方法 public abstract,抽象的
- 常量 public static final,接口中不建议使用
- 接口不能被实例化,接口中没有构造方法
- implements可以实现多个接口
- 必须要重写接口中的方法
内部类(扩展部分)
内部类就是在一个类的内部再定义一个类(扩展部分,了解即可)
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
- lambada表达式
内部类实例1
//外部类
public class Outer {
private int id = 10;
public void out(){
System.out.println("这是外部类的方法");
}
//成员内部类
public class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
//获得外部类的私有属性
public void getId(){
System.out.println(id);
}
}
//静态内部类
public static class Inner2{
public void in(){
System.out.println("这是静态内部类的方法");
}
//获得外部类的私有属性
public void getId(){
// System.out.println(id); //id不是静态属性,static方法里无法获取,静态类无法访问非静态属性和方法
}
}
public void method(){
//局部内部类可以在方法里
class Inner3{
}
}
}
//一个java类中能有一个 public class,但是可以有多个class
class A{
//可以main方法等
}
内部类实例2
public class Test {
public static void main(String[] args) {
//匿名内部类,直接 new,不赋值,不用将实例保存早变量中
new Apple().eat();
}
//调用自身的内部接口类
UserService userService = new UserService(){
@Override
public void hello() {}
};
}
class Apple{
public void eat(){
System.out.println("Apple.eat()");
}
}
//接口
interface UserService{
void hello();
}
!