• Java学习笔记3(面向对象下)


    面向对象(下)

    类的继承
    类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类称为子类,现有类称为父类,子类会自动拥有父类所有可继承的属性和方法。(用extends关键字)
     
    //定义Animal类
    class Animal{
        String name;    //定义name属性
        //定义动物叫的方法
        void shout(){
            System.out.println("动物发出叫声。");
        }
    }
    //定义Dog类继承Animal类
    class Dog extends Animal{
        //定义一个打印name的方法
        public void printName(){
            System.out.println("name = "+name);     //父类的name
        }
    }
    public class Test {
        public static void main(String[] args) {
            Dog dog = new Dog();//创建一个Dog类的实例对象
            dog.name = "tony";//为Dog类的name属性赋值
            dog.printName();//调用Dog类的printName()方法
            dog.shout();//调用Dog类继承来的shout()方法
        }
    }
    运行结果
    name = tony
    动物发出叫声。
     
    注:①只支持单继承,不允许多重继承。②多个类可以继承一个父类。③多层继承是可以的,如A继承B,B继承C。
    重写父类方法
    在子类重写的方法要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型。
    //定义Animal类
    class Animal{
        //定义动物叫的方法
        void shout(){
            System.out.println("动物发出叫声。");
        }
    }
    //定义Dog类继承Animal类
    class Dog extends Animal{
        //这里重写父类,定义狗叫的方法
         void shout(){
            System.out.println("汪汪...");
        }
    }
    public class Test {
        public static void main(String[] args) {
            Dog dog = new Dog();//创建一个Dog类的实例对象
            dog.shout();//调用Dog类继承来的shout()方法
        }
    }
    运行结果
    汪汪...
    注:子类重写父类方法时,不能使用比父类中重写的方法更严格的访问权限,如父类中的方法是public的,子类方法就不能是private。
    super关键字
    super关键字用于访问父类成员,例如访问父类的成员变量、成员方法和构造方法。
    ①使用super关键字调用父类的成员变量和成员方法。格式为:
    super.成员变量
    super.成员方法([参数1,参数2...])
    例:
    class Animal{
        String name = "动物";
        void shout(){
            System.out.println("动物发出叫声");
        }
    }
    class Dog extends Animal{
        //重写成员变量name
        String name = "犬类";
        //重写父类shout()方法
        void shout(){
            super.shout();      //访问父类的成员方法
        }
        //打印name的方法
        void printName(){
            System.out.println("name = "+super.name);   //访问父类的成员变量
        }
    }
    public class Test {
        public static void main(String[] args) {
            Dog dog = new Dog();
            dog.shout();
            dog.printName();
        }
    }
    运行结果
    动物发出叫声
    name = 动物
    ②使用super关键字调用父类的构造方法。格式为:
    super([参数1,参数2...])
    例:
    class Animal{
        //定义Animal类有参的构造方法
        public Animal(String name){
            System.out.println("我是一只"+name);
        }
    }
    class Dog extends Animal{
       public Dog(){
           super("二哈");     //调用父类有参的构造方法
       }
    }
    public class Test {
        public static void main(String[] args) {
            Dog dog = new Dog();
        }
    }
    运行结果
    我是一只二哈
    注:通过super调用父类构造方法的代码必须位于子类构造方法的第一行,并且只能出现一次。还有,在子类的构造方法中一定会调用父类的某个构造方法,可以通过super指定调用父类的某个构造方法,如果没有指定,实例化子类对象时,会自动调用父类无参的构造方法(这时如果父类中没有无参的构造方法,会报错)。
    定义一个类时,如果没有特殊要求,尽量在一个类中定义一个无参的构造方法,避免被继承时出现错误。
    class Animal{
        //定义Animal类无参的构造方法
        public Animal(){
            System.out.println("我只是一只动物");
        }
        //定义Animal类有参的构造方法
        public Animal(String name){
            System.out.println("我是一只"+name);
        }
    }
    class Dog extends Animal{
        //定义Dog类无参的构造方法
       public Dog(){
          //方法中无代码
       }
    }
    public class Test {
        public static void main(String[] args) {
            Dog dog = new Dog();
        }
    }
    运行结果
    我只是一只动物
    final关键字
    final关键字可用于修饰类、变量和方法,它有“这是无法改变的”或“最终”的含义。有以下特性:
    ①final修饰的类不能被继承
    ②final修饰的方法不能被子类重写
    当在父类中定义某个方法时,如果不希望被子类重写,就可以使用final关键字修饰该方法。
    ③final修饰的变量(成员变量和局部变量)是常量,只能赋值一次。
    注:使用final关键字修饰成员变量时,虚拟机不会对其进行初始化,因此使用final修饰成员变量时,需要在定义变量的同时赋予一个初始值。
    抽象类
    定义方法时不写方法体,该方法称为抽象方法,必须使用abstract关键字修饰。当类中包含了抽象方法,该类也必须使用abstract修饰,该类称为抽象类。
    抽象类不可以被实例化,因为抽象类中的抽象方法没有方法体,不能被调用,如果想调用抽象类中的方法,需要创建子类,在子类中将抽象类中的抽象方法进行实现。
    //定义抽象类Animal
    abstract class Animal{
        //定义抽象方法shout()
        abstract void shout();
    }
    //定义Dog类继承抽象类Animal
    class Dog extends Animal{
        //实现抽象方法shout()
        void shout(){
            System.out.println("汪汪...");
        }
    }
    public class Test {
        public static void main(String[] args) {
            Dog dog = new Dog();
            dog.shout();
        }
    }
    运行结果
    汪汪...
    接口
    如果一个抽象类中所有的方法都是抽象的,则可以将这个类用另一种方式来定义,即接口。定义接口时,需要使用interface关键字来声明。
    interface Animal{
        int ID = 1;     //定义全局常量
        void breathe();     //定义抽象方法
    }
    //接口中的变量默认使用“public static final”来修饰,即全局常量
    //接口中定义的方法默认使用“public abstract”来修饰,即抽象方法
    不能通过实例化调用接口中的方法,需要定义一个类,并使用implements关键字实现接口中的所有方法。
    下面是类与接口之间实现的关系
    //定义Animal接口
    interface Animal{
        int ID = 1;     //定义全局常量
        void breathe();     //定义抽象方法breathe()
        void run();     //定义抽象方法run()
    }
    //Dog类实现了Animal接口
    class Dog implements Animal{
        //实现breathe()方法
        public void breathe(){
            System.out.println("狗在呼吸");
        }
        //实现run()方法
        public void run(){
            System.out.println("狗在跑");
        }
    }
    public class Test {
        public static void main(String[] args) {
            Dog dog = new Dog();
            dog.breathe();
            dog.run();
        }
    }
    运行结果
    狗在呼吸
    狗在跑
    还可以定义一个接口使用extends关键字去继承另一个接口
    //定义Animal接口
    interface Animal{
        int ID = 1;     //定义全局常量
        void breathe();     //定义抽象方法breathe()
        void run();     //定义抽象方法run()
    }
    //定义了LandAnimal接口,并继承了Animal接口
    interface LandAnimal extends Animal{
        void liveOnload();      //定义C抽象方法liveOnload()
    }
    //Dog类实现了LandAnimal接口
    class Dog implements LandAnimal{
        //实现breathe()方法
        public void breathe(){
            System.out.println("狗在呼吸");
        }
        //实现run()方法
        public void run(){
            System.out.println("狗在跑");
        }
        //实现liveOnload()方法
        public void liveOnload(){
            System.out.println("狗生活在陆地上");
        }
    }
    public class Test {
        public static void main(String[] args) {
            Dog dog = new Dog();
            dog.breathe();
            dog.run();
            dog.liveOnload();
        }
    }
    运行结果
    狗在呼吸
    狗在跑
    狗生活在陆地上注:①接口中的方法都是抽象的,不能实例化对象。②当一个类实现接口时,如果这个类是抽象类,则实现接口中的部分方法即可,否则需要实现接口中的所有方法(“class A implements B{}”B中的方法必须全在A中实现出来,如果是“abstract class A implements B{}”则不需要全写)。③一个类通过implements关键字实现接口时,可以实现多个接口用逗号连接(class A implements B,C{})。④一个接口可以通过extends关键字继承多个接口用逗号连接(interface A extends B,C{})。⑤一个类在继承另一个类的同时还可以实现接口,此时,extends关键字必须位于implements关键字之前(class A extends B implements C{}    先继承,再实现)。
    多态
    在同一个方法中,由于参数类型不同而导致执行效果各异的现象就是多态。
    为了实现多态,允许使用一个父类类型的变量来引用一个子类类型的对象,根据被引用子类对象特征的不同,得到不同的运行结果。
    //定义接口Animal
    interface Animal{
        void shout();
    }
    //定义Cat类实现Animal接口
    class Cat implements Animal{
        //实现shout()方法
        public void shout(){
            System.out.println("喵喵");
        }
    }
    //定义Dog类实现Animal接口
    class Dog implements Animal{
        //实现shout()方法
        public void shout(){
            System.out.println("汪汪");
        }
    }
    public class Test {
        //定义静态的animalShout()方法,接收一个Animal类型的参数
        public static void animalShout(Animal an){
            an.shout();     //调用实际参数的shout()方法
        }
        public static void main(String[] args) {
            Animal an1 = new Cat();     //创建Cat对象,使用Animal类型的变量an1引用
            Animal an2 = new Dog();     //创建Dog对象,使用Animal类型的变量an2引用
            animalShout(an1);       //调用animalShout()方法,将an1作为参数传入
            animalShout(an2);       //调用animalShout()方法,将an2作为参数传入
        }
    }
    运行结果
    喵喵
    汪汪
    所以多态不仅解决了方法同名的问题,而且还使程序变得更加灵活,从而有效地提高程序的可扩展性和可维护性。
    对象的类型转换
    多态中,涉及到将子类对象当作父类类型使用的情况,如上面代码所写到的这两行:
    Animal an1 = new Cat();        //将Cat对象当作Animal类型来使用
    Animal an2 = new Dog();        //将Dog对象当作Animal类型来使用
    注:此时不能通过父类变量去调用子类中的某些方法(这里的某些方法指的是子类中有的方法而父类中没有)。
    //定义接口Animal
    interface Animal{
        void shout();
    }
    //定义Cat类实现Animal接口
    class Cat implements Animal{
        //实现抽象shout()方法
        public void shout(){
            System.out.println("喵喵");
        }
        //定义sleep()方法
        void sleep(){
            System.out.println("猫睡觉");
        }
    }
    public class Test {
        //定义静态的animalShout()方法,接收一个Animal类型的参数
        public static void animalShout(Animal animal){
            animal.shout();     //调用传入参数Animal的shout()方法
            //编译器检查到下面这行时,发现Animal类中没有定义sleep()方法,会报错
            animal.sleep();      //调用传入参数Animal的sleep()方法
        }
        public static void main(String[] args) {
            Cat cat = new Cat();     //创建Cat实例对象
            animalShout(cat);       //调用animalShout()方法,将cat作为参数传入
        }
    }
    以上代码会报错,所以需要进行强制类型转换,将animalShout()方法改为:
    public static void animalShout(Animal animal){
        Cat cat = (Cat) animal;     //将animal对象强制转换为Cat类型
        cat.shout();     //调用传入参数Animal的shout()方法
        cat.sleep();      //调用传入参数Animal的sleep()方法
    }
    修改后运行结果
    喵喵
    猫睡觉
    需要注意的是,在类型转换时也可能出现错误,当animalShout()方法传入Dog类型的对象时,会报错,例:
    //定义接口Animal
    interface Animal{
        void shout();
    }
    //定义Cat类实现Animal接口
    class Cat implements Animal{
        //实现抽象shout()
        public void shout(){
            System.out.println("喵喵");
        }
        //定义sleep()方法
        void sleep(){
            System.out.println("猫睡觉");
        }
    }
    //定义Dog类实现Animal接口
    class Dog implements Animal{
        public void shout(){
            System.out.println("汪汪");
        }
    }
    public class Test {
        //定义静态的animalShout()方法,接收一个Animal类型的参数
        public static void animalShout(Animal animal){
            Cat cat = (Cat) animal;     //将animal对象强制转换为Cat类型
            cat.shout();     //调用传入参数Animal的shout()方法
            cat.sleep();      //调用传入参数Animal的sleep()方法
        }
        public static void main(String[] args) {
            Dog dog = Dog();     //创建Cat实例对象
            animalShnew out(dog);       //调用animalShout()方法,将cat作为参数传入
        }
    }
    程序运行会出错,原因是在调用animalShout()方法时,传入一个Dog对象,在强制类型转换时,Animal类型的变量无法强转为Cat类型。
    针对这种情况,Java提供了关键字instanceof,它能判断一个对象是否为某个类(或接口)的实例或者子类实例,如b instanceof A ,b为子类对象或者实现类对象,
    语法:
    对象(或者对象引用变量) instanceof 类(或接口)
    对animalShout()方法进行修改后
    public static void animalShout(Animal animal){
        if(animal instanceof Cat){      //判断animal是否是Cat类的实例对象
            Cat cat = (Cat) animal;     //将animal对象强制转换为Cat类型
            cat.shout();     //调用传入参数Animal的shout()方法
            cat.sleep();      //调用传入参数Animal的sleep()方法
        }
        else
            System.out.println("这个动物不是猫");
    }
    运行结果
    这个动物不是猫
    使用instanceof关键字判断animalShout()方法中传入的对象是否为Cat类型,如果是就进行类型转换,否则输出“这个动物不是猫”。
    Object类
    Object类是所有类的父类。比如toString()方法,在该方法中输出了对象的基本信息,但也可以在其它类中用对其重写。
     
    class Animal{
        //重写Object类的toString()方法
        public String toString(){
            return "I am an Animal";
        }
    }
    public class Test {
        public static void main(String[] args) {
            Animal an = new Animal();
            System.out.println(an.toString());
        }
    }
    运行结果
    I am an Animal
    如果不对其重写会输出“类名+16进制表示的该对象哈希值”,如“Animal@b4c966a”
    匿名内部类
    之前都是用子类来实现接口,并根据该类进行实例化。除此之外,还可以使用匿名内部类来实现接口。
    匿名内部类格式:
    new 父类(参数列表)或父接口(){//匿名内部类实现部分}
     
    //定义动物类接口
    interface Animal{
        void shout();
    }
    public class Test {
        //定义静态方法animalShout()
        public static void animalShout(Animal an){
            an.shout();
        }
        public static void main(String[] args) {
            //定义匿名内部类作为参数传递给animalShout()方法
            animalShout(new Animal(){
                //实现shout()方法
                public void shout(){
                    System.out.println("喵喵");
                }
            });
        }
    }
    运行结果
    喵喵
    接下来分两步来编写匿名内部类(以便容易理解):
    ①在new Animal()后面又一对大括号,表示创建的对象是Animal的子类实例,该子类是匿名的。
    animalShout(new Animal(){});
    ②在大括号中编写匿名子类的实现代码。
    animalShout(new Animal(){
        //实现shout()方法
        public void shout(){
            System.out.println("喵喵");
        }
    });
    异常
    举一个ArithmeticExceotion异常:
    public class Test {
        public static void main(String[] args) {
            int result = divide(4,0);
            System.out.println("结果: "+result);
        }
        public static int divide(int x,int y){
            int result = x/y;
            return result;
        }
    }
    运行结果
    Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Test.divide(Test.java:7)
        at Test.main(Test.java:3)
    Throwable类中包含两大类Error类和Exception类。
    Error类称为错误类,表示Java运行时产生的系统内部错误或资源耗尽的错误,比较严重,仅靠修改程序本身是不能恢复执行的;
    Exception类称为异常类,它表示程序本身可以处理的错误。
     
    Throwable常用方法
    方法声明
    功能描述
    String getMessage()
    返回此throwable的详细消息字符串
    void printStackTrace()
    将此throwable及其追踪输出至标准错误流
    void printStackTrace(PrintStream s)
    将此throwable及其追踪输出到指定的输出流
     
    try...catch和finally
    由于发生异常,程序立即终止,无法继续执行下去,所以提供了异常的处理方式--异常捕获。异常捕获通常使用try...catch语句,格式:
    try{
    //程序代码块
    }catch(ExceptionType(Exception类及其子类) e){
    //对ExceptionType的处理
    }
    需要注意的是,在try代码块中,发生异常语句后面的代码不会被执行,如下面的“System.out.println(result);”没有执行。
    public class Test {
        public static void main(String[] args) {
            //下面的代码定义了一个try...catch语句用于捕获异常
            try{
                int result = divide(4,0);
               //发生异常,下面这条语句没被执行
                System.out.println("结果: "+result);
            }catch (Exception e){   //对异常进行处理
                System.out.println("捕获的异常信息为:"+e.getMessage());
            }
        }
        public static int divide(int x,int y){
            int result = x/y;
            return result;
        }
    }
    运行结果
    捕获的异常信息为:/ by zero
    还有finally代码块,无论是否发生异常后面代码都会被执行。由于这种特性,在程序设计时,经常会在try...catch后使用finally代码块来完成必须做的事情,例如释放系统资源。
    public class Test {
        public static void main(String[] args) {
            //下面的代码定义了一个try...catch语句用于捕获异常
            try{
                int result = divide(4,0);
                System.out.println("结果: "+result);
            }catch (Exception e){   //对异常进行处理
                System.out.println("捕获的异常信息为:"+e.getMessage());
                return;     //用于结束当前语句
            }finally{
                System.out.println("进入finally代码块");
            }
            System.out.println("程序继续向下执行...");
        }
        public static int divide(int x,int y){
            int result = x/y;
            return result;
        }
    }
    运行结果
    捕获的异常信息为:/ by zero
    进入finally代码块
    return语句用于结束当前语句,所以“System.out.println("程序继续向下执行...");”就不会执行了,而finally中的代码仍然会执行。总的来说就是不会被return语句和异常影响。
    注:当在try...catch中执行了System.exit(0)语句finally中的代码就不会执行了,System.exit(0)语句表示退出当前的Java虚拟机,任何代码都不会被执行了。还有一种是try代码块中没有代码运行finally也不会被运行。
    throws关键字
    在方法的后面使用throws关键字对外声明该方法有可能发生异常。格式:
    修饰符 返回值类型 方法名([参数1,参数2...])throws  ExceptionType1[,ExceptionType2...]{}
    如果在某方法上声明抛出异常,就必须使用try...catch对该方法进行处理,否则会报错。
    public class Test {
        public static void main(String[] args) {
            //下面的代码定义了一个try...catch语句用于捕获异常
            try{
                int result = divide(4,2);
                System.out.println("结果: "+result);
            }catch (Exception e){   //对异常进行处理
                e.printStackTrace();   //打印捕获的异常信息
            }
        }
        //下面的方法实现了两个数相除,并使用throws关键字声明抛出异常
        public static int divide(int x,int y)throws Exception{
            int result = x/y;
            return result;
        }
    }
    运行结果
    结果: 2
    使用throws关键字声明抛出异常后,即使不会出现被0除的现象,但如果不用try...catch编译程序依然会报错。
    自定义异常
    在程序开发时,有可能会用到一些自己描述的特殊的异常情况,Java中允许用户自定义异常,但自定义的异常类必须继承自Exception或其子类。
    自定义了异常,就需要用到throw关键字,throw关键字用于在方法中声明抛出异常的实例对象。格式:
    throw Exception异常对象
    下面是一个当被除数是负数时抛出自定义异常的例子。
    //下面自定义一个异常类继承自Exception
    class DivideByMinusExpetion extends Exception{
        public DivideByMinusExpetion(){
            super();    //调用Exception无参的构造方法
        }
        public DivideByMinusExpetion(String message){
            super(message);     //调用Exception有参的构造方法
        }
    }
    public class Test {
        public static void main(String[] args) {
            //下面的代码定义了一个try...catch语句用于捕获异常
            try{
                int result = divide(4,-2);
                System.out.println("结果: "+result);
            }catch (DivideByMinusExpetion e){   //对异常进行处理
                System.out.println("异常信息:"+e.getMessage());  //打印捕获的异常信息
            }
        }
        //下面的方法实现了两个数相除,并使用throws关键字声明抛出异常
        public static int divide(int x,int y)throws  DivideByMinusExpetion{
            if(y<0){
                //使用throw关键字声明异常对象
                throw new DivideByMinusExpetion("被除数是负数");
            }
            int result = x/y;
            return result;
        }
    }
    运行结果
    异常信息:被除数是负数
    下面是直接用Exception类,输出结果同上
    public class Test {
        public static void main(String[] args) {
            try{
                System.out.println(divide(4,-2));
            }catch (Exception e){
                System.out.println("异常信息:"+e.getMessage());
            }
        }
        public static int divide(int x,int y)throws Exception{
            if(y<0){
                throw new Exception("被除数是负数");
            }
            return x/y;
        }
    }
    Java中的包是专门用来存类的,通常功能相同的类存放在相同的包中。在声明包时,用package语句。
    package cn.itcast;
    public class HelloWorld {
        public static void main(String[] args) {
            System.out.println("Hello World!");
        }
    }
    运行结果
    Hello World!
    import语句
    使用import语句导包。
    如果两个类不在同一目录下,引用某个类时需要用import导包,格式:
    import 包名.类名;
    例如:import cn.itcast.Student;然后在实例化对象的时候就可以直接用Student s = new Student(); ,但如果没有导包,实例化对象时需指明位置,就得写成cn.itcast.Student s = new cn.itcast.Student(); 。
    访问控制
    Java中,针对类、成员方法和属性提供了四种访问级别,访问控制级别由小到大:private,default,protected,public。
    • private(类访问级别):如果类成员被其修饰,该成员只能被该类的其他成员访问。
    • default(包访问级别):如果一个类或者类的成员不使用任何访问控制修饰符修饰,则称则称它为默认访问控制级别,这个类或者类的成员只能被本包中的其他类访问。
    • protected(子类访问级别):如果类成员被其修饰,该成员既能被同一包下的其他类访问,也能被不同包下的子类访问。
    • public(公共访问级别):如果一个类或者类成员被其修饰,不管访问类与被访问类在不在同一个包中,都能被访问。
    注:private和protected不能修饰类,只能修饰类成员。
     
  • 相关阅读:
    python使用urllib2抓取防爬取链接
    Python 标准库 urllib2 的使用细节
    源代码阅读利器:Source Navigator — LinuxTOY
    python程序使用setup打包安装 | the5fire的技术博客
    mctop: 监视 Memcache 流量 — LinuxTOY
    nload: 监视网络流量及带宽占用
    Learn Linux The Hard Way — LinuxTOY
    使用virtualenv创建虚拟python环境 | the5fire的技术博客
    autocompleteredis 基于redis的自动补全 开源中国
    atool home
  • 原文地址:https://www.cnblogs.com/xiaochen2715/p/12036984.html
Copyright © 2020-2023  润新知