Java学习笔记-《Java程序员面试宝典》-第四章基础知识-4.2面向对象技术(4.2.7-4.2.9)

4.2.7重载和覆盖的区别

重载(overload)和覆盖(override)是Java多态性的不同表现方式。其中,重载是在一个类中多态性的表现,是指在一个类中定义了多个同名的方法,它们或有不同的参数或有不同的参数类型。具体实例,参见上篇博文(http://blog.csdn.net/qq_28814687/article/details/72722792 ) ,在使用重载是需要注意以下几点:
1>重载是通过不同的方法参数来区分的,例如不同的参数个数、不同的参数类型或不同的参数顺序
2>不能通过方法的访问权限、返回值类型和抛出异常类型来进行重载
3>对于继承来说,如果基类的方法的访问权限为private,那么就不能在派生类对其重载;如果子类也定义了和父类方法签名一样的方法,这是新的方法,是对父类方法的覆盖,不是重载。
在使用覆盖时需要注意:
1>派生类中的覆盖方法必须要和基类中被覆盖的方法具有相同的函数名、参数、返回值、抛出的异常都一致
2>如果派生类中只有返回值和基类不一样,编译器会报错
3>如果派生类中只有参数不一样,那么编译器会认为这是派生类独有的方法。
所以重载和覆盖的区别在于以下几个方面:
1>覆盖是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系;
2>覆盖只能由一个方法或着说只能由一对方法产生关系;重载可以是多个方法之间的关系;
3>覆盖要求参数列表相同;重载要求参数列表不同;
4>覆盖关系中,调用方法体是根据对象的类型(对象对应存储空间类型)来决定,即,是父类还是子类;而重载关系是根据调用时的实参表与形参表是否对应来选择方法体的。

4.2.8抽象类(abstract class)和接口(interface)有什么异同

如果一个类中包含抽象方法,那么这个类就是抽象类。在Java中,可以通过把类或者类中的某些方法声明为abstract(abstract只能修饰类或方法,不可以修饰属性)来表示一个类是抽象类。
接口就是指一个方法的集合,接口中的所有方法都没有方法体。在Java语言中,接口是通过关键字interface来实现的。
抽象类和接口都是支持抽象类定义的两种机制(前者表示的是一个实体,后者表示的是一个概念)。二者有很大的相似性,甚至有时候都是可以互换的。但同时,二者也存在很大的区别。只要包含一个抽象方法的类就必须被声明为抽象类,抽象类可以声明方法的存在而不去实现它,被声明为抽象的方法不能包含方法体。在实现时,必须包含相同的或者更低的访问级别(public->protected->private)。抽象类在使用的过程中不能被实例化,但是可以创建一个对象使其指向具体子类的一个实例。抽象类的子类为父类中的所有抽象方法提供具体的实现,否则他们也是抽象类。接口可以被看作是抽象类的变体。接口中的所有方法都是抽象的,可以通过接口来间接地实现多重继承(即实现多个接口)。接口中的成员变量都是static final类型。由于抽象类可以包含部分方法的实现,因此在一些场合下抽象类比接口存在更多的优势。

接口与抽象类的相同点如下:
1>都不能被实例化。
2>接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能被实例化。

抽象类和接口的六个不同点:
1>强调的功能点不同。接口强调特定功能的实现,设计理念是“has-a”,类似于组合;而抽象类强调所属关系,设计理念是“is-a”。
2>成员变量不同。接口只能是static final类型的常量,而且必须给其赋初值;抽象类是任意的,抽象类中的成员变量默认为default(本包可见),当然也可以被定义为其他的,这些成员变量可以在子类中被重新定义,也可以被重新赋值。
3>成员方法的实现不同。接口只能有方法的定义,不能有方法体,只有实现接口的类才能实现接口中定义的方法,其所有的成员方法都是public或abstract的,而且只能被这两个关键字修饰;抽象类可以有方法的定义与实现,即抽象类可以包含非抽象方法,而抽象方法只能是public + abstract修饰。
4>多重继承功能。一个类可以实现多个借口来间接实现多重继承的功能,而抽象类只能被一个类继承。
5>构造方法。接口没有构造方法;抽象类可以有构造方法。
6>应用。接口被运用于实现比较常用的功能,便于日后维护或者添加删除方法;而抽象类更倾向于充当公共类的角色,不适用于日后重新对里面的代码进行修改。

简单来说,接口是一种特殊形式的抽象类,使用接口完全有可能实现与抽象类相同的操作。但一般而言,抽象类用于同类食物中有无法具体描述的方法的场景,即子类与父类存在有逻辑上的”is-a”关系时,推荐使用抽象类;而接口多用于不同类之间,定义不同类之间的通信规则,希望支持差别较大的两个或者更多对象之间的特定交互行为时,应该使用接口。
接口可以继承接口,抽象类可以实现接口,抽象类也可以继承具体类。

4.2.9内部类有哪些

在Java中,可以把一个类定义到另外一个类的内部,在类里面的这个类就叫做内部类,外面的类叫做外部类。在这种情况下,这个内部类与累的属性和方法一样可以被看做外部类的一个成员。还有一种类被称为顶层类,指的是类定义代码不嵌套在其他类定义中的类。
内部类可以分很多种,主要有一下四种:静态内部类、成员内部类、局部内部类和匿名内部类。
参考网址:http://www.cnblogs.com/chenssy/p/3388487.html
1>静态内部类:是指被声明为static的内部类。通常的内部类在编译完之后会隐含的保存着一个引用,指向创建它的外围类,所以它的创建需要在外部类实例化后才能实例化。而内部类没有,所以可以不依赖于外部类实例而被实例化,而且静态内部类不能与外部类有相同的名字,不能访问外部类的普通成员变量,只能访问外部类中的静态成员和静态方法(包括私有类型)。
示例如下:

public class OuterClass {

    private String sex;
    private static String name = "chenssy";

    /**
     *静态内部类 
     * 
     */
    static class InnerClass1{

        //在静态内部类中可以存在静态变量
        private static String name1 = "chenssy_static";
        /**
         * 静态内部类只能访问外部类的静态成员变量和方法
         * 不能访问外部类的非静态成员变量和方法
         */
        public void display(){
            System.out.println("OutClass name: "+name);
        }
    }
    /**
     *  非静态内部类
     */
    class InnerClass2{

        //非静态内部类不能存在静态变量
        public String name2 = "chenssy_inner";

         // 非静态内部类中可以调用外部类的任何成员,不管是静态的还是非静态的
        public void display(){
            System.out.println("OutClass name: "+name);
        }
    }


    /**
     * 外部类方法
     * 
     */
    public void display(){
        //外部类访问内部类:内部类.
        System.out.println("InnerClass1 name: "+InnerClass1.name1);
        //静态内部类可以不依靠外部类直接创建实例
        new InnerClass1().display();

        //非静态内部类的创建需要依靠外部类
        OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
        //访问非静态内部类的成员需要非静态内部类实例
        System.out.println("InnerClass2 name: "+inner2.name2);
        inner2.display();
    }

    public static void main(String[] args){
        OuterClass outer = new OuterClass();
        outer.display();
    }

}

运行结果:
InnerClass1 name: chenssy_static
OutClass name: chenssy
InnerClass2 name: chenssy_inner
OutClass name: chenssy

2>成员内部类
成员内部类也是最普遍的内部类,他是外部类的一个成员,所以他可以无限制的访问外部类的所有成员属性和方法,尽管是private的,但是外部类要访问内部类的成员属性和方法则需要通过内部类实例来访问。
在成员内部类中要注意两点,第一:成员内部类中不能存在任何static的变量和方法;第二:成员内部类是依附于外部类的,所以只有先创建了外部类才能创建内部类。
示例如下:

public class OuterClass1 {

    private String str;

    public void outerDisplay(){

        System.out.println("outerClass...");
    }

    public class InnerClass{

        public void innerDisplay(){

            //使用外部类的属性
            str = "chenssy...";
            System.out.println(str);
            //使用外部类的方法
            outerDisplay();

        }
    }

    //推荐使用getxx()方法获取成员内部类,尤其是该内部类的构造函数无参数时
    public InnerClass getInnerClass(){
        return new InnerClass();
    }

    public static void main(String[] args){

        OuterClass1 outer = new OuterClass1();
        OuterClass1.InnerClass inner = outer.getInnerClass();
        inner.innerDisplay();


    }

}

运行结果:
chenssy…
outerClass…

3>局部内部类
局部内部类是嵌套在方法和作用域内的,对于这个类的使用主要是应用于解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。
实例如下:

class Inner1 {

    private int num = 3;

    //方法内定义局部内部类
    public void method(){

        final int num2 = 44;
        int num3 = 45;
        class PartInner{
            public void dispaly(){

                /**
                 * JDK8以下,局部内部类访问局部变量,局部变量必须要用final修饰,不然编译器就会报错
                 * 但是在JDK8以后,不用final修饰也没问题,本次运行是在JDK8以下
                 */
                System.out.println("局部变量num2 = "+num2);
            }
        }
        System.out.println("局部变量num3 = "+num3);
        //创建局部内部类
        PartInner partI = new PartInner();
        partI.dispaly();
    }
}

public class InnerDemo1{
    public static void main(String[] args){
        //局部内部类调用
        Inner1 inner = new Inner1();
        inner.method();
    }
}

运行结果:
局部变量num3 = 45
局部变量num2 = 44

4>匿名内部类
匿名内部类是一种没有类名的内部类,不使用关键字class、extends、implements,没有构造函数,但他必须继承其他类或者实现其他接口。匿名内部类的好处是代码更加简洁、紧凑,但带来的问题是易读性下降。一般应用于GUI编程中实现事件处理等。在使用匿名内部类时,要牢记一下几个原则:
1>内部类不能够有构造函数
2>匿名内部类不能定义静态成员、方法和类
3>匿名内部类不能是public、protected、private、static,即不能有修饰符
4>只能创建匿名内部类的一个实例
5>因为匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效
6>一个匿名内部类一定是在new的后面,这个匿名类必须继承一个父类或实现一个接口。
示例如下:

public class OuterClass2 {
    public InnerClass getInnerClass(final int num,String str2){
        return new InnerClass(){
            int number = num + 3;
            public int getNumber(){
                return number;
            }
        };        /* 注意:分号不能省 */
    }


    public static void main(String[] args) {
        OuterClass2 out = new OuterClass2();
        InnerClass inner = out.getInnerClass(2, "chenssy");
        System.out.println(inner.getNumber());
    }
}

interface InnerClass {
    int getNumber();
}

运行结果:
5

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值