day5 - 方法调用和面向对象(继承、封装、多态)
this关键词
在类中作为当前实例的指代关键字。
构造器
使用new关键字创建对象(使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认初始化,以及对类中构造器的调用)
类中的构造器也称构造方法,是在进行创建对象的时候必须要调用的。(如果类中没写无参构造且存在有参构造,会默认生成一个空的无参构造方法)并且构造器有以下两个特点:
-
必须和类的名字相同
-
必须没有返回类型,也不能写void
构造器作用:实例化初始值。
static
非静态方法可以直接方法类中的静态方法(因为静态方法在静态方法区中和类一起加载)
public class demo01 {
//可以用来赋初始值
{
System.out.println("匿名代码块");
}
//只执行一次
static {
System.out.println("静态代码块");
}
public demo01(){
System.out.println("构造方法");
}
public static void main(String[] args) {
demo01 t1 = new demo01();
System.out.println("===========");
demo01 t2 = new demo01();
}
}
/*输出结果为:
静态代码块
匿名代码块
构造方法
===========
匿名代码块
构造方法
*/
静态导入包
//静态导入包,可以直接使用方法
import static java.lang.Math.random;
public class demo01 {
public static void main(String[] args) {
System.out.println(random());
}
}
创建对象内存分析
public class Pet {
String name;
int age;
public void shout(){
System.out.println(this.name + " shout!");
}
}
public class demo01 {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "AKK";
dog.age = 3;
dog.shout();
Pet cat = new Pet();
}
}
图示:
面向对象
-
面向对象编程(Object-Oriented Programming,OOP)
-
面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。
三大特性
封装
即数据的隐藏,通常应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。(通过get/set方法进行调用和存储)
继承
继承的本质是对某一批类的抽象。
关键词:extends(拓展)。子类是父类的拓展。
Java中类只有单继承,没有多继承!(一个儿子只能有一个父亲,一个父亲可以有多个儿子)
-
继承是类和类之间的一种关系。除此之外,类和类的关系还有依赖、组合、聚合等
-
继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
-
子类与父类之间,从意义上讲应该具有“is a”的关系。
子类继承了父类,拥有父类的全部方法!(前提是公开的,即public)
object类
在Java中,所有的类都默认直接或间接继承object类,即object类是所有类的父类。
super
注意点:
-
super调用父类构造方法,必须放在构造方法的第一个
-
super必须只能出现在子类的方法或者构造方法中!
-
super和this不能同时调用构造方法(两者都要放在第一个)
super VS this:
代表的对象不同:
-
this:本身调用者这个对象
-
super:代表父类对象的应用
前提:
-
this:没有继承也可以使用
-
super:只能在继承条件中使用
构造方法:
-
this():本类的构造
-
super():父类的构造
方法重写
重写都是方法的重写,与属性无关。
重写需要有继承关系,子类重写父类的方法
-
方法名必须相同
-
参数列表必须相同
-
修饰符:范围可以扩大但不能被缩小(public->protected就不行)
-
跑出异常:范围可以被缩小,但不能扩大:(ClassNotFoundException -->Exception(大)就不行)
-
子类方法和父类方法必要一致,但方法体不同!
重写的原因:父类的功能,子类不一定需要,或不一定满足!
实例:
public class B {
public static void test() {
System.out.println("B—》test()");
}
public void test1() {
System.out.println("B—>test()");
}
}
public class A extends B{
public static void test() {
System.out.println("A—》test()");
}
public class Demo {
public static void main(String[] args) {
//静态方法的调用只和定义的类型(等式左边)有关
//非静态方法:重写(public)
A a =new A();
B b = new A();//子类重写了父类的方法
a.test();
b.test();
System.out.println();
a.test1();
b.test1();
}
}
/*输出的结果为:
A—》test()
B—》test()
A—>test()
A—>test()
*/
多态
接口的多种不同的实现方式即为多态。
我们在程序中定义的引用变量所指向的具体类型和通过该引用变量的方法调用在编程的时候并不确定,当处于运行期间才确定。就是这个引用变量究竟指向哪一个实例对象,在编译期间是不确定的,只有运行期才能确定,这样不用修改源码就可以把变量绑定到不同的类实例上,让程序拥有了多个运行状态,这就是多态。
即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
注意事项:
-
多态是方法的多态,属性没有多态。
-
多态存在于父类和子类
-
多态存在的条件:继承关系,方法需要重写,父类引用指向子类对象! Father f1 = new Son();
无法重写:
-
static方法,属于类,但不属于实例
-
final,常量
-
private方法,私有的,无法重写
多态分为编译时多态和运行时多态:
-
编译时多态:重载(根据实际参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法中的哪一个)
-
运行时多态:重写(如果子类和父类都有相同的方法,则父类方法被子类方法重写,使用子类的方法,如果父类有而子类没有,则使用父类方法)
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Student();
//new Father();
//子类能调用的方法都是自己的或是继承父类的
Son s1 = new Son();
//父类的引用指向子类的类型
//父类型可以指向子类,但是不能调用子类独有的方法
/*
Java运行时和动态对象绑定的
程序运行前,它不知道会调用哪些方法
而且类型之间存在类型转换,例如((son)s2).eat();
*/
Father s2 = new Son();
Object s3 = new Son();
s1.run();
//子类重写了父类的方法
s2.run();
//对象能执行哪些方法,主要看对象左边的类型,和右边关系不大
s1.eat();
//s2.eat();//会报错
}
public class Father {
public void run(){
System.out.println("Father run");
}
}
public class Son extends Father {
instanof
instanof是用来判断两个对象的继承关系
public static void main(String[] args) {
//Object > String
//Object > Father > Son
//Object > Father > Pet
Object object = new Son();
System.out.println(object instanceof Son);//ture
System.out.println(object instanceof Father);//ture
System.out.println(object instanceof Object);//ture
System.out.println(object instanceof Pet);//false
System.out.println(object instanceof String);//false
System.out.println("===============");
Father father = new Son();
System.out.println(father instanceof Son);//ture
System.out.println(father instanceof Father);//ture
System.out.println(father instanceof Object);//ture
System.out.println(father instanceof Pet);//false
//System.out.println(father instanceof String);编译会报错
}
类型转换
public class demo01 {
public static void main(String[] args) {
//类型之间的转化:
// 基本类型转化:高转低要强制类型转化,反之则不用
//低转高:Son son = new Son();->Father son = new Son();
//高转低:
Father obj = new Son();
((Son) obj).go();//强制类型转换
//子类转换为父类:可能会丢失自己本来的一些方法
}
}
public class Father {
public void run(){
System.out.println("run");
}
}
public class Son extends Father {
public void go(){
System.out.println("go");
}
}
-
父类引用指向子类对象(前提)
-
把子类转换成父类,向上转型;
-
把父类转换成子类,向下转型;强制转换
-
方便方法调用,减少重复的代码,更简洁(更抽象)
-
从认知论的角度考虑,先有对象后有类。对象是具体的事物,类是抽象的概念,是对对象的抽象。
-
从代码运行角度考虑是先有类后有对象。类是对象的模板。
-
用《苏菲的世界》的话来说,对象是盒子里的姜饼人(物质),类是概念中的姜饼人(灵魂)。
-
从抽象程度:封装->继承->多态->抽象类->接口
-