美文网首页
[Java]开发安卓,你得掌握的Java知识6——封装、继承、多

[Java]开发安卓,你得掌握的Java知识6——封装、继承、多

作者: 入梦瞌睡 | 来源:发表于2019-08-10 23:34 被阅读0次

    目录

    1.本文主要内容简介

    2.基础知识讲解

    3.知识实际运用

    4.总结

    0.前言

    1.本文主要内容简介

    • 代码块
    • 内部类
    • 封装、继承、多态
    • 一个实际的例子(思路、代码)

    2.基础知识讲解

    2.1什么是代码块

    • 从观角度来说,
      代码块就是在类中,用{ }括起来的部分

    • 从程序运行的角度来讲
      代码块就像静态属性、方法一样,会早于对象被创建

    • 一个程序可以有多个代码块,执行顺序是从上倒下
      但是注意:
      尽可能不要写多个代码块(因为没有意义,可以写在一起)

    class Person{
        int age;
        {
            age = 20;
            System.out.println("代码块 age="+age);
        }
        {
            age=30
            System.out.println("代码块 age="+age);
        }
    
    }
    
    • 代码最后输出为:
      代码块 age=20
      代码块 age=30
    • 用“static”修饰的代码块是静态代码块
      静态代码块就和静态方法一样,会在对象创建前就被创建,因此
      静态代码块只能调用静态属性、方法
        static{
           //静态代码块
        }
    

    2.2什么是内部类

    • 按字面意思理解即可,内部类就是写在其他类内部的类

    • 内部类出现的原因主要是因为某些类需要依附着别的类

    • 定义内部类的好处在于:
      (1)内部类实际上是一种很好的封装
      (2)内部类拥有外围类的所有元素的访问权限
      (3)内部类在外围类被某个子类继承时,内部类会跟着继承

    内部类的一些细节:

    • 如果有内部类,一般会在外围类的属性中,
      声明一个内部类变量(不赋值)
    • 一般为了封装性好,我们不会让外部去调用我们的内部类,
      一般不能让Test.InnerTest.方法名()出现
      (当然真这样写程序不会报错,但是封装性会变差)

    • 为了避免上面的这种情况,我们会在外围类的某个方法中,将已经声明过的内部类的变量用new进行赋值,然后根据内部类的构造方法等函数使用内部类

    • 为了封装性,最关键就是让外部不知不觉地调用内部类,而不是显式调用

    public class Test{
       int count;
       InnerTest inner;
       class InnerTest{
           //这是一个内部类
           public InnerTest(){
                //这是内部类的构造方法
                count = 2;
                show();
           }
       }
       
       public void test(){
           //这个函数是给外部调用的
           inner = new InnerTest();
       }
       public void show(){
            System.out.println("内部类构造函数被执行了");
       }
    }
    
    public static void main(String[] args){
          Test temp = new Test();
          temp.test();
    }
    
    • 终端会输出:内部类构造函数被执行了
    上面这段代码看似有点复杂,我们慢慢理一下
    • 首先,外围类叫做Test,内部类叫做InnerTest

    • 在上面代码的main函数中,我们创建了一个Test类(外围类)对象,然后调用了该类的一个对象方法test();

    • test()为Test中的inner属性用new进行赋值,使得内部类的构造函数被调用

    • 内部类的构造函数中,调用了外围类的show(),所以终端输出了那句话

    2.4什么是继承

    • 某个准备编写的类A中的内容,和已存在的类B中很相似,或者A中的内容是B的一个延伸拓展,那么我们不会傻乎乎地再从头写一遍A
      而是让A去继承B

    • class A extends B , 表示类A是继承类B的

    • 当A继承了B后,A就可以使用B的属性、方法(即使A中没有声明)

    • Java中只能单继承,不能多继承,最多只能间接多继承
      即(A继承B,B继承C,相当于A继承C,变相多继承)

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

    class Person{
        protected String name;
        protected int age;
    
        public Person() {
    
        }
    
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        public void walk(){
            System.out.println("走");
        }
    }
    
    
    class Student extends Person{
        public String school;
        public int id;
    
        public Student(String name, int age, int id, String school) {
            super(name,age);
            this.id = id;
            this.school = school;
            this.age = age;
            this.name = name;
        }
    
        @Override
        public void walk() {
            System.out.print("学生优雅地");
            super.walk();
        }
    }
    
    上面代码的注意点:
    • 父类为Person类,子类为Student类

    • 父类想要保证属性的私有性,又要保证能够被继承,会让属性被protected修饰

    • public与protected修饰的属性是可以被继承的,但是private不行

    • 如果父类中,已经写了一个有参的构造函数,那么子类再写有参的构造函数且要用到父类属性的时候,需要写一个super(参数...)
      来说明哪些属性来自于父类

    2.5什么是重写

    • 重写就是子类将父类的方法拿到自己这里进行修改

    • 重写的方法一般会在上面加上 @Override,来表示这是重写的方法

    • 重写与重载是两码事
      重写是针对继承来说的,是子类修改父类的方法
      重载是针对一个类来说的,是类中会有多个同名的方法,但是这些方法的参数种类、数量,以及方法返回值都不尽相同

    @Override
        public void walk() {
            System.out.print("学生优雅地");
            super.walk();
        }
    

    上面的代码就是重写,其中super表示父类super.walk()就表示
    这次重写除了自己新增那部分,还要用到父类的方法

    2.6什么是多态

    • 多态简单来说有两种体现:
      (1)同一个方法(在不同类中)有多种不同的实现(与重载不一样)
      (2)如果有继承关系(必须的前提,直接继承、间接继承都行)
      子类的对象可以使用父类变量接收(叫做“类型的向上转换”)

    • 多态关注的是同一个方法在不同类中的实现,
      重载是同一个方法名但是参数、返回值不同

    class A{
    }
    class B extends A{
    }
    A test = new B();
    Object test2 = new B();
    List<Integer> list = new ArrayList<>();
    

    这些都是多态的体现,当然更实际一些的应用在于:

    class Person{}
    class Student extends Person{}
    class Teacher extends Person{}
    Student s1 = new Student();
    Teacher t1 = new Teacher();
    ArrayList<Person> list = new ArrayList<>();
    list.add(s1);
    list.add(t1);
    
    • 在写ArrayList的泛型的时候,如果要添加多种数据类型,而且这些数据类型都是继承的同一个类,那么就可以把这个统一的父类写在泛型中

    3.实际应用

    • 定义一个Person类:有name age两个属性
      提供有参数的构造方法
      walk方法
      eat方法

    • 公务员:salary(工资) , show()
      公司职员:salary ,会什么技术tec(字符串),show()

    • 创建多个职员和公务员 放到一个数组里面
      将数组里面所有人的信息输出(把所有方法都显示出来)

    要完成这个小程序,要一步步考虑:
    (1)需要将多个人放到数组里
    (2)放到数组里的要分为两种类型,公务员类和公司职员类
    (3)这两个类都继承与Person类,还有自己的属性salary等
    (4)Person类中有两个属性name age
         以及两个方法walk(),eat()
    (5)两个继承类均有自己的show()方法来展示信息

    • 我们首先要定义一个Person类,并构造一个有参的构造方法。
      这个父类基本不需要怎么处理,照着要求做即可
    public class Person {
        public String name;
        public 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("人会吃");
        }
    }
    
    • 然后,我们需要按要求写两个继承类
      Clerk(银行职员)和CivilServant(公务员)
      没什么难度,因为子类没有什么额外的方法
    public class Clerk extends Person {
        public int salary;
        private String tec;
    
        public Clerk(String name, int age, int salary) {
            super(name,age);
            this.salary = salary;
        }
        @Override
        public void walk() {
            System.out.print(" 快跑 ");
        }
    
        @Override
        public void eat() {
            System.out.print(" 吃得快 ");
        }
    
    }
    
    public class CivilServant extends Person {
        public int salary;//薪水
    
        public CivilServant(String name, int age, int salary) {
            super(name,age);
            this.salary = salary;
        }
    
        @Override
        public void walk() {
            System.out.print(" 大步走 ");
        }
    
        @Override
        public void eat() {
            System.out.print(" 大方吃 ");
        }
    
    }
    
    • 接下来问题在于如何把人放入数组中
      为了方便,我们定义几个静态数组来存放默认的人以及他们的信息,这些静态数组方法Constant类中
    public class Constant {
        public static String[] PERSONS = {"小王","小红","小黑","小蓝"};
        public static int[] PERSONSAGES = {20,19,25,16};
        public static String[] OCCUPATIONS= {"CivilServant","Clerk","CivilServant","Clerk"};
        public static int CIVILSERVANTSALARY = 10000;
        public static int CLERKSALARY = 5000;
        public static String[] TEC= {"Android开发","iOS开发"};
    }
    
    • 有了这些信息之后,我们就需要将这些信息放入ArrayList中,由于CivilServant与Clerk虽然是不同的类,但是都继承于Person类
      因此ArrayList的泛型就可以写<Person>

    • 为了封装性好一些,我们可以专门定义一个PersonManager,来处理人的信息(比如把信息打包放入数组中)

    public class PersonManager {
        public List<Person> personList = new ArrayList<>();
        
    }
    
    • 我们在PersonManager里面写一个方法来把静态数组中的信息放入personlist中
    public void InfoInput(){
            //用来将Constant类中的内容放入数组中
            for (int i = 0; i < Constant.PERSONS.length; i++) {
                if (Constant.OCCUPATIONS[i] == "CivilServant") {
                    this.personList.add(new CivilServant(Constant.PERSONS[i],Constant.PERSONSAGES[i],Constant.CIVILSERVANTSALARY));
                }else{
                    //否则就是Clerk
                    this.personList.add(new Clerk(Constant.PERSONS[i],Constant.PERSONSAGES[i],Constant.CLERKSALARY));
                }
    
            }
        }
    
    • 其中,通过判定OCCUPATIONS来判断是那种职位,分别调用两种不同的构造函数(使用的是匿名对象)
      所有信息都从Constant中定义好的静态数组中获取
    • 最后我们写一个方法来输出,其中要注意的是,
      父类是无法使用子类的方法的,要使用子类的方法,
      就必须把父类强制转换为子类

      如下面代码中的 Clerk c = (Clerk)p;,然后通过c调用show()方法
     public void showWorkerInfo(){
            //将所有人的所有信息都显示出来
            for(Person p : personList){
                if(p instanceof CivilServant){
                    CivilServant c = (CivilServant)p;
                    c.show();
                }else{
                    //是银行职员
                    Clerk c = (Clerk)p;
                    c.show();
                }
            }
        }
    

    别忘记还要再两个继承类中添加show()方法:

    public void show() {
            System.out.print("name:" + this.name + " age:" + this.age + " salary:" + this.salary + " 公务员会");
            this.walk();
            this.eat();
            System.out.println();
        }
    
    public void show() {
            System.out.print("name:" + this.name + " age:" + this.age + " salary:" + this.salary + " 银行职员会");
            this.walk();
            this.eat();
            System.out.println();
        }
    

    通过以上的封装后,主函数就可以写的比较清晰简洁了

    public static void main(String[] args) {
            //创建一个PersonManager对象
            PersonManager personManager = new PersonManager();
            
            //把所有人放入数组中
            personManager.InfoInput();
    
            //把输出所有人
            personManager.showWorkerInfo();
    
        }
    

    输出结果为:

    name:小王 age:20 salary:10000 公务员会 大步走 大方吃
    name:小红 age:19 salary:5000 银行职员会 快跑 吃得快
    name:小黑 age:25 salary:10000 公务员会 大步走 大方吃
    name:小蓝 age:16 salary:5000 银行职员会 快跑 吃得快

    ps:代码只是用来做个例子,输出结果没有任何其他意思

    4.总结

    (1)今天主要讲解了与类的继承有关的知识,继承、多态、封装也算是面向对象的灵魂,需要多多注意
    (2)继承、多态等新知识,实际上理论都不难,但是如果想要灵活运用,还是需要多多练习
    (3)可以发现,Java的代码编写一直都离不开“封装”的思想,因此,日后的学习中,锻炼这一思想,应该要当做一个重点看待。

    相关文章

      网友评论

          本文标题:[Java]开发安卓,你得掌握的Java知识6——封装、继承、多

          本文链接:https://www.haomeiwen.com/subject/nytdjctx.html