面向对象进阶

面向对象进阶

1类的继承

概念

  • 类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被当作子类,现有的类被称作父类

  • 使用extends关键字来声明一个类继承另一个类

  • 一个类只能继承自一个父类,多个类可以继承父类,父类可以继承自其他父类,父类和子类是相对概念

  • 调用子类构造器时会先调用父类的构造器

    public class Person {
        protected String name="person's name";
        public Person()
        {
            System.out.println("Person无参构造执行了");
        }
        
        public void print()
        {
            System.out.println("person");
        }
    }
    
    
    public class Student extends Person{
        private String name="student's name";
        public Student(){
            //隐藏代码 调用父类构造器
            System.out.println("Student无参构造执行了");
        }
    }
    
    public class Demo {
        public static void main(String[] args)
        {
            Student s1=new Student();
            s1.test();
        }
    }
    

重写父类方法

  • 在继承关系中,子类会自动继承父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类方法的重写
  • 在子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值的类型

public class Person {
    protected String name="person's name";
    public Person()
    {
        System.out.println("Person无参构造执行了");
    }

    public void print()
    {
        System.out.println("person");
    }
}
public class Student extends Person{
    private String name="student's name";
    public Student(){
        //隐藏代码 调用父类构造器
        System.out.println("Student无参构造执行了");
    }
    //重写了父类方法
    public void print()
    {
        System.out.println("student");
    }
}

public class Demo {
    public static void main(String[] args)
    {
        Student s1=new Student();
        //print被重写了,所以此时调用的是子类的print(),会输出student
        s1.print();
    }
}

super关键字

  • 当子类重写父类的方法后,子类对象将无法访问父类被重写的方法

  • super关键字可以用于访问父类的成员

    
    public class Person {
        protected String name="person's name";
        public Person()
        {
            System.out.println("Person无参构造执行了");
        }
    
        public void print()
        {
            System.out.println("person");
        }
    }
    
    public class Student extends Person{
        private String name="student's name";
        public Student(){
            //隐藏代码 调用父类构造器
            System.out.println("Student无参构造执行了");
        }
        public void print()
        {
            System.out.println("student");
        }
        public void test1(){
            print();//student
            this.print();//调用子类的构造方法,此时会输出student
            super.print();//调用父类的构造方法,此时会输出person
        }
        public  void test()
        {
            System.out.println(this.name);
            System.out.println(super.name);
        }
    }
    
public class Demo {
    public static void main(String[] args)
    {
        Student s1=new Student();
        s1.test();
    }
}

2final关键字

  • final修饰的类不能被继承
  • final修饰的方法不能被子类重写
  • final修饰的变量(成员变量和局部变量)是常量,只能被赋值一次

3抽象类和接口

抽象类的特点

1.不能new这个类,只能靠子类去实现它

2.抽象类可以写普通的方法

3.抽象方法必须在抽象类中

  • 代码
//abstract 抽象类的关键字
public abstract class Action {
    //约束,等待子类实现
    //abstract抽象方法,只有方法的名字,没有方法的实现
    public abstract void doSomething();

}
//继承自抽象类的方法,必须实现父类(抽象类)的所有方法,除非该类也是抽象类
public class A extends Action {
    @Override
    public void doSomething() {

    }
}

接口

  • 接口与其他类的区别

    • 普通类:只有具体实现
    • 抽象类:具体实现和规范(抽象方法)都有
    • 接口:只有规范,自己无法写方法,定义的是一种规则
  • interface

//interface 定义的关键字,接口都需要有实现类
public interface UserService {
    //接口里定义的属性都是常量
    int AGE=99;
    //接口中的所有定义其实都是抽象的public abstract
    void add(String name);
    void delete(String name);
    void update(String name);
    void query(String name);
}

//类 可以实现接口 implements一个接口
//实现了接口中的类,必须要重写接口中的方法
public class UserServiceImp1 implements UserService {

    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void update(String name) {

    }

    @Override
    public void query(String name) {

    }
}
  • 接口的作用
    • 实现约束(常量都是 public static final 方法都是 public abstract,实现接口必须重写接口中的方法)
    • 定义一些方法,让不同的人实现
    • 接口可以实现多继承(接口不能被实例化,没有构造方法)

4多态

类型转化

  • 在同一个方法中,由于参数类型不同而导致执行效果各异的现象就是多态

  • 为了实现多态,允许使用一个父类类型的变量来引用一个子类类型的对象,根据被引用子类对象特征的不同,得到不同的运行结果。

  • 将子类对象当作父类对象时不需要任何显示声明,但是此时不能通过父类对象来调用子类的方法

  • 将父类对象变成子类对象要向下转型,要显示声明

    
    public class Demo {
        static public void main(String[] args)
        {
            //高         低
           Person person=new Student();
           //子类转化为父类可能会丢失方法,此时obj不再能用StudentEat()
            //Student将这个对象转化为Student类型,我们就可以使用Student类型的方法了
            ((Student)person).StudentEat();
    
            //低         高
            //Student student=new Person();这样转直接报错
            Person person1=new Person();
            //此时把person1转化为student,并赋值给student
            Student student=(Student)person1;
    
        }
    }
    
    public class Person {
        public void run()
        {
            System.out.println("run");
        }
        public void PersonSay()
        {
            System.out.println("say");
        }
    }
    
public class Teacher2 extends Person{
    void print()
    {
        System.out.println("teacher");
    }
}
public class Student extends Person{
    //重写了父类的run
    public void run()
    {
        System.out.println("student run");
    }
    public void StudentEat()
    {
        System.out.println("eat");
    }
}

instanceof

  • 用于判断一个对象是什么类型的(判断有没有类的继承关系)

    public class Person {
        public void run()
        {
            System.out.println("run");
        }
    
    }
    
    
    public class Student extends Person{
        //重写了父类的run
        public void run()
        {
            System.out.println("student run");
        }
        public void eat()
        {
            System.out.println("eat");
        }
    }
    
    public class Teacher2 extends Person{
        void print()
        {
            System.out.println("teacher");
        }
    }
    
    
    public class Demo {
        static public void main(String[] args)
        {
            //x instanceof Y能不能编译通过看两者有没有关系,是ture就有继承关系,是false就同级
            //Object>Person>Student
            //Object>Person>Teacher
            //Object>String
            Object s1=new Student();
            System.out.println(s1 instanceof Object);   //有继承关系,输出true
            System.out.println(s1 instanceof Person);   //有继承关系,输出true
            System.out.println(s1 instanceof Student);  //有继承关系,输出true
            System.out.println(s1 instanceof String);   //有继承关系,输出true
            System.out.println(s1 instanceof Teacher);  //有继承关系,输出true
    
            Person s2=new Student();
            System.out.println(s2 instanceof Object);   //有继承关系,输出true
            System.out.println(s2 instanceof Person);   //有继承关系,输出true
            System.out.println(s2 instanceof Student);  //有继承关系,输出true
            System.out.println(s2 instanceof Teacher2); //student和teacher同级 输出false
          //  System.out.println(s2 instanceof String);   //编译报错,没有关联
            System.out.println();
            Student s3=new Student();
            System.out.println(s3 instanceof Object);   //有继承关系,输出true
            System.out.println(s3 instanceof Person);   //有继承关系,输出true
            System.out.println(s3 instanceof Student);  //有继承关系,输出true
           // System.out.println(s3 instanceof String);   //无关 编译报错
           // System.out.println(s3 instanceof Teacher2);  //无关 编译报错
        }
    }
    
    

object类

常用方法

方法名称方法说明
equals()指示其他某个对象是否与此对象"相等"
getClass()返回Object的运行时类
hashCode()将对象的内存地址进行哈希运算,返回int类型的一个值
toString()返回该对象的字符串表示

匿名内部类

  • 在定义匿名内部类的地方往往直接创建一个该类的对象

    public class Demo {
        public static void main(String[] args) {
            //定义一个内部类Cat实现Animal接口
            class Cat implements Animal{
                //实现shout方法
                @Override
                public void shout() {
                    System.out.println("miao~");
                }
            }
            animalShout(new Cat());
    
        }
        //定义静态方法
        //内部类Cat实现了Animal接口,在调用animalShout()方法时,将Cat类的实例对象作为参数传入方法中
        public static void animalShout(Animal an){
            an.shout();//调用传入对象an的shout方法
        }
    }
    
public interface Animal {
    void shout();
}

5异常

Error&Exception

  • 检查性异常:最具代表性的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略

  • 运行时异常:

    • 运行时异常可以在编译时被忽略
    • 一般由程序逻辑错误引起,可以被捕获
  • 错误Error:

    • 错误不是异常,而是脱离程序员控制的问题,在编译时也检查不到的
    • Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
    • 是灾难性的错误,一般JVM会选择终止线程

异常体系结构

  • Java把异常当作对象类处理,并定义一个类java.lang.Throwable作为所有异常的超类

  • 异常类分为两大类,错误Error和异常Exception

  • 详见https://www.jianshu.com/p/49d2c3975c56

异常处理机制

  • 抛出异常

  • 捕获异常

  • 异常处理五个关键字

    • try

    • catch

      • 捕获异常,括号里是捕获异常的类型,类型级别可以参考体系结构
      • 可以写多个,级别按从上到下的顺序从小到大写
    • finally

      //idea快速生成:ctrl+alt+t
      public class demo1 {
          public static void main(String[] args) {
              int a=1;
              int b=0;
      
              try{//try监控区域
                  System.out.println(a/b);
              }catch (ArithmeticException e){//catch捕获异常,里面的参是想要捕获的异常类型
                  System.out.println("程序出现异常,变量b不能为0");
                  e.printStackTrace();//打印错误的栈信息
              }finally {//处理善后工作。可有可无,但是关闭的操作一般放在finally里面
                  System.out.println("finally");
              }
          }
      }
      
    • throw

    • throws

      public class demo1 {
          public static void main(String[] args) {
              try {
                  new demo1().test(1,0);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          public void test(int a,int b){
              if(b==0){
                  throw new ArithmeticException();//主动抛出异常
              }
              //即使没有这行也会抛出异常
              System.out.println(a/b);
          }
      }
      

    自定义异常

    • 使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可

    • 在程序中使用自定义异常类,大体可分为以下几个步骤:

      1.创建自定义异常类

      2.在方法中通过throw关键字抛出异常对象

      3.如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。

      4.再出现异常方法的调用者中捕获并处理异常

    public class MyException extends Exception{
        //传递数字>10就抛出异常
        private int detail;
    
        public MyException(int a){
            this.detail=a;
        }
        public String toString(){
            return "MyException"+detail;
        }
    }
    
    public class Test {
        //可能会存在异常的方法
        static void test(int a)throws MyException{
            if(a>10){
                throw new MyException(a);//抛出异常
            }
            System.out.println("ok");
        }
    
        public static void main(String[] args) throws MyException {
            try {
                test(11);
            } catch (MyException e) {
                //e.printStackTrace();
                System.out.println("MyException"+e);
            }
        }
    }
    

    经验总结

    • 处理运行异常时,采用逻辑去合理规避同时辅助try-catch处理
    • 在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
    • 对于不确定的代码,可以加上try-catch,处理潜在的异常
    • 尽量去处理异常,切忌只是简单地调用printStackTrace()去打印输出
    • 具体如何处理异常,要根据不同的业务需求和异常类型去决定
    • 尽量添加finally语句块去释放占用的资源
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值