目录
1.继承
1.1继承的概念
继承是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了 由简单到复杂的认知过程。
1.2继承的语法
class Animal{
String name;
int age;
}
class Cat extends Animal{
}
这里的cat类就是继承了Animal类
1.3继承的作用
继承可以让子类具有父类的属性和方法,达到简化代码的目的
我们举个例子来看
class Animal{
String name = "asd";
int age;
}
class Cat extends Animal{
public void call(){
System.out.println(name + "正在喵喵叫");
}
}
public class Main {
public static void main(String[] args) {
Cat cat = new Cat();
cat.call();
}
}
这里我们的Cat类继承了Animal类,所以我们可以直接在Cat类中使用父类中的name变量,我们得到的结果如下
注意:子类会将父类中的成员方法,成员变量全都继承到子类中,并且子类中必须要有自己的特有成员或者方法,体现出和父类的不同,否则的话继承就没有任何意义了
1.4super的作用
①当子类和父类中的变量重名时,想要调用父类的变量,就可以用super,例如
class Animal{
String name = "asd";
int age;
}
class Cat extends Animal{
String name = "asdfasdfa";
public void call(){
System.out.println(super.name + "正在喵喵叫");
}
}
得到的结果依然是
这里我们明显的可以看出来,用super调用的是父类中的成员变量
注意:super和this一样,是建立在对象的基础上使用的,被static修饰的变量将不能用super调用
总结:成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时 再到父类中找,如果父类中也没有则报错。
②当子类和父类中的方法重名时
当子类和父类中的方法重名时,想要调用父类的方法,就可以用super,例如
class Animal{
String name = "asd";
int age;
public void call(){
System.out.println(name + "正在叫");
}
}
class Cat extends Animal{
String name = "asdfasdfa";
public void call(){
System.out.println(name + "正在喵喵叫");
super.call();
}
}
在这里我们的运行结果也可以明显的表现出super访问父类成员,运行截图如下
③子类构造方法
在我们子类进行继承的时候,如果父类构造方法需要传参数,那么我们应该先给父类完成构造,才能对子类进行初始化。例如
class Animal{
String name = "asd";
int age;
public Animal(String name,int age){
this.name = name;
this.age = age;
}
public void call(){
System.out.println(name + "正在叫");
}
}
class Cat extends Animal{
String name = "asdfasdfa";
public Cat(String name,int age){
super(name,age);
this.name = name;
this.age = age;
}
public void call(){
System.out.println(name + "正在喵喵叫");
super.call();
}
}
这里我们通过子类的构造方法中,用super关键字,对父类的构造方法进行构造,如果不进行构造的话,编译器会报错,所以我们要注意,在父类有构造方法并且带参数的时候,子类需要对父类的构造方法先进行构造,然后才能执行自己的构造方法
注意:super(...)只能在子类构造方法中出现一次,且在第一行,并且不能和this同时出现。
④this和super的比较
相同点:
1.都只能在类的非静态方法中使用,用来访问非静态的方法和字段
2.在构造方法中调用的时候,都必须是第一条语句
不同点:
1.this是当前对象的引用,super是子类从父类继承下来那部分对象的引用
2..this是非静态成员方法的一个隐藏参数,super不是隐藏的参数
3.构造方法中一定会存在super(...)的调用,用户没有写编译器也会增加,但是this(...)用户不写则没有
1.5练习小题
看如下代码,说出他的执行结果
class Person {
public String name;
public int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person:构造方法执行");
}
{
System.out.println("Person:实例代码块执行");
}
static {
System.out.println("Person:静态代码块执行");
}
}
class Student extends Person {
public Student(String name, int age) {
super(name, age);
System.out.println("Student:构造方法执行");
}
{
System.out.println("Student:实例代码块执行");
}
static {
System.out.println("Student:静态代码块执行");
}
}
public class MyArrayList {
public static void main(String[] args) {
Student student1 = new Student("张三", 19);
System.out.println("===========================");
Student student2 = new Student("gaobo", 20);
}
public static void main1(String[] args) {
Person person1 = new Person("bit", 10);
System.out.println("============================");
Person person2 = new Person("gaobo", 20);
}
}
我们在知道,静态代码块优先执行于非静态代码块,那我们可以分析一下这个题目
最后的结果是
这里我们可以看到,父类的静态代码块会优先于子类的静态代码块,然后会依次执行父类中的实例代码块和构造方法,然后是子类的,你作对了嘛?
1.6继承方式
在JAVA中,我们允许的继承方式是单继承和多层继承,还有就是一个父类被很多子类继承,不支持一个子类继承多个父类
注意:当一个类被final修饰的之后,这个类便不能再被继承了
2.多态
2.1多态的概念
2.2实现多态的条件
2.3多态的实现
class Animal{
String name = "asd";
int age;
public Animal(String name,int age){
this.name = name;
this.age = age;
}
public void call(){
System.out.println(name + "正在叫");
}
}
class Cat extends Animal{
String name = "asdfasdfa";
public Cat(String name,int age){
super(name,age);
this.name = name;
this.age = age;
}
public void call(){
System.out.println(name + "正在喵喵叫");
}
}
class Dog extends Animal{
public Dog(String name,int age){
super(name,age);
this.name = name;
this.age = age;
}
public void call(){
System.out.println(name+"汪汪叫");
}
}
public class Main {
public static void TestCall(Animal animal){
animal.call();
}
public static void main(String[] args) {
Cat cat = new Cat("miaomiao",5);
TestCall(cat);
Dog dog = new Dog("大黄",10);
TestCall(dog);
}
}
在这段代码中,我们的Dog和Cat都对Call方法进行了重写,我们都调用了TestCall方法,但是我们传进去的参数不同,那么他进行的叫就不同,这里我们涉及到了向上转型,后面会讲,这里先大概知道有多态这么个东西
代码执行结果是:
2.4向上转型
向上转型就是把子类的对象赋值给父类类型的变量
上述代码中,我们将Cat和Dog类型的对象作为参数传给TestCall,并且用Animal进行了接收,在形参接收实参的过程中,就发生了向上转型,也就是Animal类型的变量接收了一个Cat类型的对象,这就叫向上转型
2.5动态绑定
在我们发生向上转型之后,往往会发生动态绑定,也就是当我们调用向上转型后对象的方法时,编译器会调用子类的方法,从而达到了多态的效果,也就是在上述代码中,我们在TestCall中调用了call方法,当我们传得的是Cat时,就发生了向上转型,转型之后,这个call方法就会变成Cat中重写的call方法,这中情况我们称之为动态绑定,从而实现了多态的效果
2.6多态的优缺点
优点:让代码的实现变得更家灵活了
缺点:1.无法调用子类中特有的方法了
例如
从这里可以看到,我们调用Dog中特有的方法eat之后,编译器发生了报错
2.代码的执行效率变低了
2.7注意事项
避免在构造方法中使用多态
直接看代码
class B {
public B() { // do nothing func(); }
public void func () {
System.out.println("B.func()");
}
}
class D extends B {
private int num = 1;
public void func() {
System.out.println("D.func() " + num);
}
}
public class Test {
public static void main(String[] args) {
D d = new D();
}
}
这段代码中,因为B的构造方法先执行,然后B中的func和D中的func发生了动态绑定,所以B中构造方法的func执行的其实时D中的func然后此时的num并没有赋值,所以是0,而且B的func并没有执行
所以执行结果是
D.func()0
这里插入一个instanceof
这个方法是用来查看是否转型成功的就比如我想知道我的Animal是否向下转型成为了Dog
if(animal instanceof Dog)
如果是,则结果为true