Java内部类,继承,多态的学习

一、学习目的

继承简化了人们对事物的认识和描述,能清晰体现相关类间的层次结构关系。在实际操作中,多态可以让我们不用关心某个对象到底是什么具体类型,就可以使用该对象的某些方法,而这些方法通过一个抽象类或者接口来实现,多态就是提供父类调用子类代码的一个手段。

二、学习内容

(1)代码块

一般情况下,如果有些代码需要在项目启动的时候就执行,这时需要用到代码块。

如何在创建对象之前先做点准备工作?

  • 1,构造方法

  • 2,静态变量

  • 3,静态方法 但必须要主动调用才执行

  • 4,代码块 代码块在对象创建之前就优先被调用,即优先于构造方法被调用
    结构:
    【修饰符】{
    预先执行的语句;
    }

     public class MyClass {
     static{
     System.out.println("静态代码块");
     }
    }
    

注意 :

  • 修饰符只有static和缺省;
  • 类里面有多个代码块,按从上到下先后执行,若后面的内容和前面的的内容相同,后面的内容覆盖前面的内容;
  • 尽量不要在类里面写多个代码块;
  • 静态代码块里面不能调用成员变量和实例方法 ,但可以调用静态成员变量;
(2)内部类

内部类: 所谓内部类就是在一个类内部进行其他类结构的嵌套操作。
定义一个类 可以在多个地方定义一个类,创建类的地方:

  • 1,单独创建一个文件管理一个类

  • 2,直接在文件里面 ,类的上面和下面创建

  • 3,直接在某个类的内部创建一个类
    为什么需要内部类?
    希望一个类A依附于另一个类B

     class RelativeLayout{
     String view;
     //在显示一个视图之前 必须告诉系统这个视图的具体位置
     public void show(float leftMergin,float topMergin,float rightMergin,float 
     bottomMergin){
     System.out.println("视图"+view+"显示出来了");
     System.out.println("left:"+leftMergin+"  top:"+topMergin+
             "  right:"+rightMergin+"  bottom:"+bottomMergin);
     }
     //定义一个内部类 用于管理相对布局的具体布局属性
     public static class LayoutParams{
     float leftMergin;
     float topMergin;
     float rightMergin;
     float bottomMergin;
     public LayoutParams(float leftMergin,float topMergin,float rightMergin,float bottomMergin){   //构造方法
         this.leftMergin = leftMergin;
         this.topMergin = topMergin;
         this.rightMergin = rightMergin;
         this.bottomMergin = bottomMergin;
       }
      }
    }
    

上述代码定义了一个LayoutParams内部类用于管理布局的具体布局属性
访问该静态内部类的方法:
第一种

            RelativeLayout.LayoutParams params =  //创建内部类的对象
            relativeLayout.new LayoutParams(20f,20f,20f,20f);
             relativeLayout.show(params);

第二种 只有静态的内部类才能这样用 但此时又不算一个的内部类了,因为它能在外部使用 ,所以尽量不要在类的内部创建静态内部类

    //show里面的是一个匿名类
  relativeLayout.show(new RelativeLayout.LayoutParams(20f,20f,20f,20f));
    relativeLayout.show(20f,20f,20f,20f);

若不是静态内部类的使用方法:直接调用外部类的show方法即可

    relativeLayout.show(20f,20f,20f,20f);

内部类构造方法的调用:

 class TestInner{
 int a;
int b;
Inner inner;
class Inner{
         //非静态的内部类,这个内部类类就可以引用外部类的属性和方法
    public Inner(){
        a = 20;
        b = 30;
        show();
    }
}
public void test(){
    inner = new Inner();    //调用内部类的构造方法
}
public void show(){
    System.out.println("a = "+a);
  }
}

调用,输出结果为a = 20;执行孙旭是先调用外部类的test方法,test方法里面在调用内部类的构造方法 给a赋值20;

   TestInner testInner= new TestInner();
    testInner.test();  
(3)继承

继承 获得父类的属性和方法,并且可以自己添加一些属性和方法 使用关键字extends
class A extends B ,B是A父类

  • Java只能单继承 但可以变相的多继承 例如A继承B,B继承C,则A继承B,C,利用接口也可以实现变向多继承

  • 所有的类都是直接或间接继承Object类

  • 如果调用子类的方法,如果没有就回到父类里面查找, 如果子类里面需要调用父类的方法或者显示调用父类的属性,用super
    什么情况下 需要在一个方法里面调用super的方法?
    如果一个方法需要完成一个功能 又不能单独完成 必须要父类做相应的工作
    1,父类做完之后,子类在操作
    2,子类做点事情后,在调用父类去完成
    父类:

     class Person{
      String name;
      int age;
      public Person(String name,int age){
     this.name = name;
     this.age = age;
    }
     public void walk(){
     System.out.println(name+"在散步");   
     }
       public void eat(){
        System.out.println(name+"在吃饭");
       }
     }
    

子类:

class Student extends Person{
int id;
String school;
public Student(String name,int age,int id,String school){
    super(name,age);   //父类存在有参构造方法,所以要先调用父类的有参构造方法
    this.id = id;
    this.school = school;
}
// 重写toString
 @Override
 public String toString() {
    return "Student{" +
            "name='" + name + ''' +
            ", age=" + age +
            ", id=" + id +
            ", school='" + school + ''' +
            '}';
   }
  //方法的重写
@Override
public void walk() {
    super.walk();
    System.out.println("学生优雅的走");
}
@Override
public void eat() {
    super.eat();
    System.out.println("学生小口吃饭");
}
}

注意: 如果子类需要重新实现父类的方法 就需要重写,重写的方法前面加Override,例如子类中的walk(),eat()方法重写饭方法是也用super调用了一下父类原有的方法,但在构造方法重写时:若父类的是无参构造方法,子类可以直接重写构造方法;若父类里面存在有参的构造方法,则需要用super()先调用父类的构造方法,然后在为其他变量赋值,例如上面的子类的构造方法里面调用父类的构造方法super(name,age);

测试一下:

   class TestExtends{
   public static void main(String[] args){  
    Student xwj = new Student("xwj",20,10010,"SWU"); //创建一个子类对象
    xwj.walk();  //调用子类重写的函数
    xwj.eat();
    System.out.println(xwj);
  }
}

结果:

测试结果
(4)多态

多态(polymorphic)

  • 1,以同一个方法在不同的子类中有不同的实现
  • 2,如果有继承关系 子类的对象可以使用父类的对象接收
    类型的向上转换 父类型可接收子类型

多态的应用的具体展现在下面的小实例里面

三、实例应用

定义一个person类,在定义一个公务员类,一个公司员工类,存在同一个数组里,然后在输出每个人的基本信息
Person类:

package swu.xwj.day5.MessageManager;
public class Person {
String name;
int age;
public Person(String name,int age){
    this.name = name;
    this.age = age;
}
public void walk(){
    System.out.println("人在走路");
}
public void eat(){
    System.out.println("人在吃饭");
 }
}

CivilServant类:

package swu.xwj.day5.MessageManager;
public class CivilServant extends Person{
int salary;
int workTime;
public CivilServant(String name,int age,int salary,int workTime){
    super(name,age);
    this.salary = salary;
    this.workTime = workTime;
}
public void show(){
    System.out.println("姓名:"+name+"  年龄:"+age+"工作:公务员"+"  每天工作小时:"+workTime
    +"  薪水:"+salary);
}
@Override
public void walk() {
    System.out.println("公务员走路");
}
@Override
public void eat() {
    System.out.println("公务员吃饭");
}
@Override
public String toString() {
    return "CivilServant{" +
            "salary=" + salary +
            ", newspaper=" + workTime +
            ", name='" + name + ''' +
            ", age=" + age +
            '}';
    }
 }

Cilk类:

 package swu.xwj.day5.MessageManager;
 public class Clerk extends Person {
 int salary;
String thch;
public Clerk(String name,int age,int salary,String thch){
    super(name,age);
    this.salary = salary;
    this.thch = thch;
}
public void show(){
    System.out.println("姓名:"+name+"  年龄:"+age+"  工作:公司员宫"+"  技术:"+thch+"  薪水"+salary);
}
@Override
public void walk() {
    System.out.println("公司员工走路");
}
@Override
public void eat() {
    System.out.println("公司员工吃饭");
} 
@Override
public String toString() {
    return "Clerk{" +
            "salary=" + salary +
            ", thch='" + thch + ''' +
            ", name='" + name + ''' +
            ", age=" + age +
            '}';
   }
 }

main方法类:

  package swu.xwj.day5.MessageManager;
  import java.util.ArrayList;
  public class MyClass {
  public static void main(String[] args){
     ArrayList persons = new ArrayList(); //定义一个数组保存所有人
     CivilServant cs1 = new CivilServant("xw",20,5000,4);
     CivilServant cs2 = new CivilServant("xl",23,5500,5);//创建五个CivilServant类的对象
     CivilServant cs3 = new CivilServant("zs",27,6000,7);
     CivilServant cs4 = new CivilServant("xwj",30,5000,4);
     CivilServant cs5 = new CivilServant("xwz",40,8000,10);
     persons.add(cs1); //向数组里添加对象
     persons.add(cs2); 
     persons.add(cs3);
     persons.add(cs4);
     persons.add(cs5);
     Clerk cl1 = new Clerk("dsa",24,10000,"IOS");  //创建五个Cilk类的对象
     Clerk cl2 = new Clerk("zsa",25,13000,"Android");
     Clerk cl3 = new Clerk("fsa",26,14000,"Android");
     Clerk cl4 = new Clerk("dea",21,9000,"IOS");
     Clerk cl5 = new Clerk("na",27,7000,"Android");
     persons.add(cl1);  //向数组里添加对象
     persons.add(cl2);
     persons.add(cl3);
     persons.add(cl4);
     persons.add(cl5);
     for(Person person:persons){
         //找到person到底是哪个类型的对象
         if(person instanceof CivilServant){
             CivilServant cs = (CivilServant)person;   //强制转换
             cs.show();
             cs.walk();
             cs.eat();
             cs.toString();
         }else{
             Clerk cl = (Clerk)person;
             cl.show();
             cl.walk();
             cl.eat();
         }
      }
  }
}

分析:由于要把公务员和公司员工放到一个数组里面,但数组只能存放容易中数据类型的元素,但Cilk和CivilServant是两个不同的类,但由于二者都继承于Person类,所以只要把数组类型设置为Person类,这样就可以把二者都存进去,这就体现了Java的多态性,也可以把数组类型设置为Object类型,因为所有的类都继承这个类。到后面输出信息时,要判断数组元素到底是哪个类型的,然后在强制转换成CivilServant类或Cilk类这样才能调用相应的show方法,用instanceof关键字判断。

四、学习感悟

今天的学习内容虽然比较多,但是相对而言比较简单,理解起来也不算麻烦,但在真正实际使用的时候会有点小迷茫,但仔细想一下也能清楚,这种情况就是练习的太少,所以不管那点内容,即使是简单知识,也需要不断地练习,不能眼高手低。