1 继承
继承是面向对象的三大特征之一(封装、继承、多态),它可以解决代码的冗余问题,从而实现代码的重用。新类可以在不增加自身代码的基础上,通过从当前类中继承其属性和方法来充实自身,这就是继承。新的类称为子类,现有的类称为父类。
注:java只支持单继承,即一个子类只能继承一个父类。父类可以有多个子类,例如:狗属于动物,猫也属于动物,猫类、狗类都可以继承父类(动物类。)
1.1 继承的语法
[访问修饰符] class 子类类名 extends 父类类名{
}
注: 1、访问修饰符是public,则该类在整个项目中可见,不写访问修饰符,该类只在当前包中可见。
2、子类与父类在不在同一个包中,子类都可以继承public和protected修饰的属性和方法
3、不写访问修饰符(即默认访问修饰符)情况下,子类和父类必须在同一个包中。
4、子类不能继承父类的构造方法
public class Animal {//父类
String name;
String brand;
public void run(){
}
}
--------------------------------------------------
public class Dog extends Animal{//子类
public Dog() {
this.name="狗仔";//继承父类的属性
this.brand="中华田园犬";
}
public static void main(String[] args){
Dog dog=new Dog();
System.out.println(dog.name);//继承父类的属性
dog.run();//继承父类的方法
}
}
1.2 使用super调用父类的成员
super关键字和this关键字的用法是一样的。区别在于:super关键字调用父类的成员属性和方法,也可以调用父类的构造方法,this关键字调用自身的属性和方法。
访问父类的构造方法:super(参数)
public class Animal {//父类
String name;
String brand;
public Animal(){
}
public Animal(String brand){
this.brand=brand;
}
}
-------------------------------
public class Dog extends Animal{//子类
public Dog() {
super();//访问父类的无参构造
}
public Dog(String brand) {
super(brand);//访问父类的有参构造
}
}
访问父类的属性和方法:super.父类属性/父类方法() ;
public class Animal {//父类
String name;
String brand;
public void run(){
}
}
-------------------------------
public class Dog extends Animal{//子类
public Dog() {
super.brand="中华田园犬";//使用super访问父类的属性(不常用,父类的属性子类也拥有,可以使用this调用)
}
public void run(){
super.run();//调用父类的方法
}
}
注:super只能出现在子类(子类的方法和构造方法中)
super用来访问父类的属性、方法、构造方法
super无法访问父类的private成员
1.2 子类的实例化
在java中,一个类的构造方法只有在下面两个情况中才会被执行;
1、创建该类的对象时(该类的实例化)
2、创建该类子类的对象时(子类的实例化)
也就是说,子类实例化的是时候,会先执行父类的相应的构造方法。换句话说,java会先执行父类的构造方法,在执行子类的构造方法。其规则如下:
1、如果子类,没有使用super关键字调用父类的构造方法,或者使用this关键字调用自身的其他的构造方法。系统会默认调用父类的无参构造方法;
public class Animal {
String name;
String brand;
public Animal(){
this.name="大大";
System.out.println(this.name);
}
public void run(){
System.out.println("跑得快");
}
}
----------------------------------------------------------
public class Dog extends Animal{
int age;
public Dog(){
//super();无论 super() 是否存在,都先执行父类的无参构造
this.name="小小";
this.age=3;
System.out.println(this.name);
}
public static void main(String[] args){
Dog dog=new Dog();//执行父类的无参构造,结果为:大大 小小
}
}
2、如果子类使用super调用父类的有参构造方法,那么则执行父类的有参构造方法,而不执行父类的无参构造方法
public class Animal {
String name;
String brand;
public Animal(String brand){
this.brand=brand;
System.out.println(this.brand);
}
public void run(){
System.out.println("跑得快");
}
}
-------------------------------------------------
public class Dog extends Animal{
int age;
public Dog(String brand){
super(brand);
System.out.println(this.brand);
}
public static void main(String[] args){
Dog dog=new Dog("阿拉斯加雪橇犬");//先执行父类的有参构造
}
}
3、如果子类使用this关键字调用自身的其他构造方法,在相应的构造方法遵循以上原则
public class Animal {
String name;
String brand;
public Animal(){
System.out.println(this.brand);
}
public Animal(String brand){
this.brand="阿拉斯加";
this.brand=brand;
System.out.println(this.brand);
}
public void run(){
System.out.println("跑得快");
}
}
---------------------------------------------------------
public class Dog extends Animal{
int age;
public Dog(){
this.brand="哈士奇";
System.out.println(this.brand);
}
public Dog(String brand){
this.brand=brand;//默认调用父类的无参构造方法(隐式调用)
}
public Dog(String brand,String name){
this(brand);//this显示调用含参构造方法,
this.name=name;
System.out.println(this.name);
}
public Dog(String brand,String name,int age){
this();//this显示调用无参构造方法
this.name=name;
System.out.println(this.name);
}
public static void main(String[] args){
Dog dog=new Dog("哈士奇");//先执行父类的无参构造方法
}
}
1.3 方法的重写
子类可以根据句自己的需求对父类的方法进行修改,以符合自己的要求,这就是方法的重写。
注: 1、重写的方法必须和被重写的方法 方法名称相同、相同的参数类型及其个数。
2、重写的方法必须和被重写的方法 返回值必须相同 。
3、重写方法不能降低被重写方法的权限。
4、子类重写方法时,缩小被重写方法的权限。 就会导致类的多态性无法使用
public class Animal {
String name;
String brand;
void run(){
System.out.println("跑得快");
}
}
---------------------------------------------------
public class Dog extends Animal{
int age;
public void run(){
//方法的重写
System.out.println(this.name+"在"+this.age+"的时候跑得快");
}
public static void main(String[] args){
Dog dog=new Dog();
dog.run();
}
}
2 多态
1.多态是java面向对象的三大特征之一,多态是指呈现多种不同的形态。在Java中,则指一个特定类型的变量可以去引用不同类型的对象。并且可以自动的调用引用对象的方法。换句话说,就是根据作用到的不同的类型,响应不同的操作。
2.1方法的重写是实现多态的基础。
//方法的重写
//父类
public class Pet {
public void toHospital(){
System.out.println("宠物看病");
}
}
-----------------------------------------------
public class Bird extends Pet{
public void toHospital(){
//bird继承父类Pet的方法,并重写方法
System.out.println("小鸟看病");
}
}
----------------------------------------------
public class Dog extends Pet{
public void toHospital(){
System.out.println("狗狗看病");
}
}
//多态的调用
public class Test {
public static void main(String[] args) {
Pet dog=new Dog();//父类Pet的变量指向调用dog的实例
dog.toHospital();//狗狗看病 //多态调用的就是子类的方法
Pet bird=new Bird();
bird.toHospital();//小鸟看病
}
}
2.2 向上转型与向下转型
2.2.1 基本数据类型的转型
在基本数据中,double类数据是大于int数据的,在转换的时候,int数据向double数据转换时,是自动转换的。反过来,则需要强制转换。向上转型与向下转型既是如此。
父类是大类,子类是小类。小转大自动转换,大转小强制转换。
Pet pet=new Dog();//多态为向上转型,小转大。
(Dog) dog=(Dog)new Pet();//向下转型是小转大,需要强制转换
注:1.向下转型,父类变量指向子类的实例,此时父类的对象只可以调用子类继承或者覆盖父类的方法,不能调用子类特有的(父类没有的)方法。
2.父类需要调用子类特有的方法,就需要进行向下转型。
3.转型与多态有关,而多态一般是指向上转型,即父类变量指向子类的实例。在进行向下转型之前,我们需要判断父类变量是否指向我们需要的子类的实例,而不是其他的子类实例。就需要用到instanceof运算符来判断。
//父类
public class Pet {
public void toHospital(){
System.out.println("宠物看病");
}
}
-----------------------------------------
public class Bird extends Pet{
public void toHospital(){
System.out.println("小鸟看病");
}
public void fly(){//鸟类特有的方法
System.out.println("小鸟会飞");
}
}
------------------------------------------
public class Dog extends Pet{
public void toHospital(){
System.out.println("狗狗看病");
}
public void catchingFlyDisc(){//Dog类特有的方法
System.out.println("狗狗会接飞盘");
}
}
-----------------------------------------------
public class Test {
public static void main(String[] args) {
Pet pet=new Dog();//多态指向Dog类
pet=new Bird();//多态指向Bird类
if(pet instanceof Dog){//判断父类Pet是否指向了Dog的实例
Dog dog=(Dog)pet;//若指向Dog类,则进行向下转型,来调用子类特有的方法
dog.catchingFlyDisc();
}else if(pet instanceof Bird){
Bird bird=(Bird)pet;
bird.fly();
}
}
}
2.3 多态的应用
从上面案例分析可得多态的优势:
可替换性:多态对已经存在的代码具有可替换性。
可扩充性:新增加的子类不会影响已经存在的类的继承性与多态性及其它的性质。
接口性:多态是父类向子类提供的一个共同的接口,有子类来具体实现。
灵活性:应用中的多态体现了灵活多样的操作,提高了使用效率。
简化性:多态简化了软件的代码编写与修改过程。
2.3.1 父类作为方法的形参:
public class Host {//主人类
public void letCry(Animal animal){//Animal类作为方法的参数
animal.Cry();
}
}
--------------------------------------------------------------------
public abstract class Animal{
//父类
public void Cry(){};
}
--------------------------------------------------------------------
public class Cat extends Animal{
public void Cry(){//子类
System.out.println("猫咪会哭");
}
}
--------------------------------------------------------------------
public class Bird extends Animal {
public void Cry(){//子类
System.out.println("小鸟会哭");
}
}
--------------------------------------------------------------------
public class Test {
public static void main(String[] args) {
Host host=new Host();
Animal animal;//父类变量
animal=new Cat();//多态应用 指向Cat类的实例
host.letCry(animal);//猫咪会哭
animal=new Bird();//多态应用 指向Bird类的实例
host.letCry(animal);//小鸟会哭
}
}
2.3.2 父类作为方法的返回值:
public class Host {
//主人类
public Animal DonateAnimal(String type){
Animal animal;//父类变量
if(type=="dog"){
animal=new Dog();//多态指向Dog类
}else if(type=="bird"){
animal=new Bird();//多态指向Bird类
}else{
animal=new Cat();//多态指向Cat类
}
return animal;
}
}
---------------------------------------------------
public class Animal{
//父类
public void Cry(){
System.out.println("宠物会哭");
}
}
---------------------------------------------------
public class Bird extends Animal {
//鸟类
public void Cry(){
System.out.println("小鸟会哭");
}
}
---------------------------------------------------
public class Cat extends Animal{
//Cat类
public void Cry(){
System.out.println("猫咪会哭");
}
}
---------------------------------------------------
public class Dog extends Animal {
//Dog类
public void Cry(){
System.out.println("狗狗会哭");
}
}
---------------------------------------------------
public class Test {
public static void main(String[] args) {
Host host=new Host();
Animal animal;//父类变量
animal=host.DonateAnimal("dog");
animal.Cry();//调用Dog类的方法
animal=host.DonateAnimal("cat");
animal.Cry();//调用Cat类的方法
}
}