• 三大特性:(经典代码)


     1.定义一个Person类

    public class Person {
        
        private String name;  // 姓名
        private int age;      // 年龄
        
        public Person() {    // 无参构造
            super();
        }
        public Person(String name, int age) {  // 有参构造
            super();
            this.name = name;
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        
       
        
        @Override  // 重写toString()方法
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }
        
        public void show() {
            System.out.println("Person类中的show()方法");
        }
        
        
        
    }

     2.写一个Student 学生类

    public class Student extends Person {
        private int id;   // 学号
        
        public Student() {  // 无参构造
            super();
        }
    
        public Student(String name, int age,int id) {   // 有参构造
            
            super(name,age);  // 调用父类中的构造方法
            this.id = id;
        }
    
    
         //提供供外界访问的 get/set()方法
        public int getId() {
            return id;
        }
    
    
        public void setId(int id) {
            this.id = id;
        }
    
         @Override
        public String toString() {
            return "Student [id=" + id +" name="+getName()+" age="+getAge()+ "]";
        }
    
    
        @Override
        public void show() {
            System.out.println("Student类中重写后的show()方法");
             
        }
    }

    3.写一个 Teacher 教师类

    package com.monkey1024;
    
    public class Teacher extends Person {
        
        private double salary;  // 工资
    
        public Teacher() {
            super();
        }
    
        public Teacher(String name, int age,double salary) {
            super(name, age);
            this.salary = salary;
        }
    
        public double getSalary() {
            return salary;
        }
    
        public void setSalary(double salary) {
            this.salary = salary;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + getName() + ", age=" + getAge() + ", salary="+salary+"]";
        }
    
        @Override
        public void show() {
             System.out.println("Teacher类中重写后的show()方法");
        }
    
    }

    测试类:

    public class Test {
    
        public static void main(String[] args) {
            
            // 创建一个学生类
            Student student = new Student("小茅棚",23,01);   // 姓名,年龄,学号
            System.out.println(student);
            student.show();
            System.out.println("--------------------");
            
            // 创建一个教师类
            Teacher teacher = new Teacher("马云",55,88888.8); // 姓名, 年龄, 工资
            System.out.println(teacher);
            teacher.show();
    
        }
    
    }

    控制台结果:

    Student [id=1 name=小茅棚 age=23]
    Student类中重写后的show()方法
    --------------------
    Person [name=马云, age=55, salary=88888.8]
    Teacher类中重写后的show()方法
    

    重点:

    子类继承父类,

    若子类 没有重写 父类的方法,则 运行阶段 调用从父类中继承的对应方法  -----如该程序中的,show()方法

    若子类 重写了父类中的方法, 则 运行阶段 调用自己重写之后的该方法。

    注意:

    无论是否重写父类的方法,在编译阶段 程序统一都是调用父类中的该方法。

    (这就是为什么,虽然子类中对父类方法进行了重写,但是一旦删除父类中被重写的方法,程序立马报错的原因)


     测试类中写如下内容:

    public class Test {
        
        // 定义一个静态的print()方法,既能打印人类的功能,又能打印老师的功能 还能能打印学生的功能
    public static void print(Person p) { // 形参要的是是一个Person类型 p.show(); } public static void main(String[] args) { Test.print(new Person()); System.out.println("--------------"); Test .print(new Student()); System.out.println("--------------"); Test.print(new Teacher()); } }

    控制台结果:

    Person类中的show()方法
    --------------
    Student类中重写后的show()方法
    --------------
    Teacher类中重写后的show()方法
    

     public static void print(Person p) {      

    该方法中要求的是一个 Person类型的引用作为方法的形参

    在main()方法的代码中,把Person类的子类 Student类的引用 和 Teacher类的引用作为形参 传递 过去,并不报错。且运行阶段 调用的是他们各自的方法。


    代码改进:

         如 Person类中,有 name 和 age属性,其中age代表的是年龄。

         生活经验告诉我们,年龄通常不能小于0,且通常不会超过150岁。

        但是在以上的代码中,将age设置为负数 或 888,程序也正常运行。这显然是不符合逻辑的。

    改动代码:

    在setAge()方法中 对传入的 age值做合理值 判断

     public void setAge(int age) {
            if(age>0 && age<=150) // 判断条件
            this.age = age;
            else
                System.out.println("年龄输入不符合常理....");
        }

    在构造方法中将 this.age= age; 改为setAge(age);

    public Person(String name, int age) {  // 有参构造
            super();
            this.name = name;
            // this.age = age;
            setAge(age);    
        }

    测试:

    System.out.println(new Person("james",888));

    控制台打印结果:

    年龄输入不符合常理....
    Person [name=james, age=0]
    

     同理,像salary、id 等属性 都最好 传值前做合理值判断,来避免发生夸张不合常理的运算结果


    让程序产生异常:

    若传入不符合常理的age值,当然也可以使用暴力点的方式处理问题直接让程序产生异常     

    1.先自定义一个异常:AgeException 年龄值异常

    // 自定义一个异常: id异常
    public class AgeException extends Exception {
         
        public AgeException() {   // 无参构造
            
        }
        
       public AgeException(String str) {   // 有参构造
            super(str);
        }
        
        
    
    }

    2.Person类中修改代码:setAge()方法

    public void setAge(int age) throws Exception {
            if(age>0 && age<=150)
            this.age = age;
            else
                // System.out.println("年龄输入不符合常理....");
                throw new AgeException("年龄输入不符合常理.....");    // 这里指定要抛出AgeException异常类型
        }

    3.将程序报警的每个地方进行,异常的抛出 或 异常的捕获 处理

    4.test代码:

    public class Test {
        
     public static void main(String[] args) throws Exception {    // 异常的向上抛出
         
         Student student = new Student("Bob",-1,1002);   // 年龄值 传递了一个 -1
         System.out.println(student);
     System.out.println("-------------"); }

    控制台打印结果:

    Exception in thread "main" com.monkey1024.AgeException: 年龄输入不符合常理.....
        at com.monkey1024.Person.setAge(Person.java:32)
        at com.monkey1024.Person.<init>(Person.java:15)
        at com.monkey1024.Student.<init>(Student.java:16)
        at com.monkey1024.Test.main(Test.java:7)

    还有注意:

    super();   // 写在子类构造方法体的首行,表示 调用父类中的无参构造

    super(属性类型1,属性值1, 属性类型2 属性值2...);  //表示调用父类中对应的有参构造

    super.父类方法();      // 写在子类重写之后的方法体内,表示 调用父类中的该方法

    this关键字 表示 --"当前对象"    谁调用该方法,this 代表的就是 谁这个对象


    多态:

                父类类型的引用 指向 子类类型的对象      ===>  形成多态!!!

     测试代码:

    public class Test {
        
     public static void main(String[] args) {
         
         //Person类型的引用p 指向 Student类型的对象 形成 多态
         Person p = new Student();
         p.show();
         
         
        //Person类型的引用p 指向 Teacher类型的对象 形成 多态
         p = new Teacher();
         p.show();
         
    }
    
    }
    
    
    控制台结果:
    Student类中重写后的show()方法
    Teacher类中重写后的show()方法

    分析:

     p.show();
    

     虽然是Person类型的引用p调用show()方法,但是运行出来的结果表明:执行的是子类各自的重写之后的show()方法

    其中:

                父类类型的引用 指向 子类的对象, 子类 is a 父类
               Person p = new Student();   此时,发生了 Student类型 向 Person类型的自动类型转换 

    子类 is a 父类,父类有的方法,子类也一定可以调用。



    产生问题:那么父类可以调用子类中的方法吗?

     Person ps = new Student("Bob",24,1002);
         ps.show();
         
         // ps.getId();       编译报错,是因为ps是Person类型的引用。父类类型的引用不能直接调用子类类型的方法
    Student ts=(Student)ps; //做了强制类型转换:将Person类型的ps 强转为 Student类型 int res = ts.getId(); System.out.println(res); }
    
    
    
    通过上面代码可以知道:
    父类类型的引用 要想访问 子类特有的方法,则需要进行 强制类型转换才能访问。 (父类引用直接访问子类属性则编译报错)

    再思考一问题:若把 Person类型的引用 强制 转换 为String类型,再调用String类中length()方法能不能成功?
    res = ((String)ps).length();  // 编译报错
    
    
    
    报错的原因:String类 与 Person类之间,不存在 父子类 关系!!!

    再思考一问题:那么是不是只要存在父子类关系,父类的引用就可以转换成任意的子类类型后也能执行成功呢?
    public class Test {
        
      public static void main(String[] args) {
         
         Person ps = new Student("Bob",24,1002);   // ps指向的是Student类型的对象
         ps.show();
         Student ts=(Student)ps;    // 编译成功
         int res = ts.getId();
         System.out.println(res);  // 且运行成功
         
         System.out.println("-------------");
         
         Teacher t=(Teacher)ps;   // 编译阶段 成功
     
         
      }
    }
    控制台结果:
    Student类中重写后的show()方法
    1002
    -------------
    Exception in thread "main" java.lang.ClassCastException: com.monkey1024.Student cannot be cast to com.monkey1024.Teacher
        at com.monkey1024.Test.main(Test.java:15)
     从输出结果发现:产生了java.lang.ClassCastException,类型转换异常

    Teacher t=(Teacher)ps; // 编译阶段 成功
    这行代码能够成功通过编译阶段, 但是在运行阶段报错了。

    编译通过-----因为Teacher类 与 Person类之间确实存在父子关系,
    运行报错----- Person ps = new Student("Bob",24,1002); ps真正指向的是Student对象,并不是Teacher。其实进行的是Student类型 转 Teacher类型,肯定报错!
    ps真正指向的是Student类型的对象,而非Teacher类型的对象。


    所以,代码在运行阶段的错误风险更高。为了避免类型转换异常的发生,添加判断:判断ps引用真正 指向 的对象是否为 Teacher类型即可!
    public class Test {
        
     public static void main(String[] args) {
         
         Person ps = new Student("Bob",24,1002);
         ps.show();
         Student ts=(Student)ps;    // 编译成功
         int res = ts.getId();
         System.out.println(res);  // 且运行成功
         
         System.out.println("-------------");
         
         if(ps instanceof Teacher) {     // instanceof关键字 判断 ps真正的指向类型是不是Teacher类型
             Teacher t=(Teacher) ps;
    System.out.println(
    "ps可以放心地转换为Teacher类型"); }else { System.out.println("ps不能强制转换为Teacher类型"); } } }
    
    
    

    运行结果:
    Student类中重写后的show()方法
    1002
    -------------
    ps不能强制转换为Teacher类型
    
    
    
    
    
    instance关键字的作用


     

  • 相关阅读:
    什么是 DLL?
    如何用vc创建和读取xml文件??
    VC中调用 Excel 的总结
    Excel.cpp和Excel.h
    SQL中也可以用格式字符串定制日期转字符串
    REVERT权限切换
    透明数据加密
    批量恢复数据库
    FILESTREAM
    eclipse Tomcat热启动maven install Jrebel
  • 原文地址:https://www.cnblogs.com/penguin1024/p/11734890.html
Copyright © 2020-2023  润新知