thinking in java 多态,接口,内部类,异常小结

来源:互联网 发布:喜剧动漫 知乎 编辑:程序博客网 时间:2024/05/21 17:38

多态


1.类内private方法是禁止覆盖的和继承的,它默认为final。
在派生类中使用名字最好和基类名字不同

2.类方法中的数据域一般为private,我们调用getter它方法来访问它,setter方法来设置它,如果你直接访问某个域而不是传引用,多态会在编译进行解析

3.static方法不具有多态性,它是所有此类对象共有的

4.构造器默认为static的,构造方法是从基类构造到派生类,因为派生类有可能会用到基类的方法,java有GC回收,所以我们不用构建销毁方法,但是如果我们想手动销毁,必须是先销毁派生类在销毁基类,构造和销毁顺序相反。
并且我们要显示调用销毁方法。

5.如果存在多个引用时,我们不能直接调用销毁方法,必须增加引用计数方法。

6.在派生类构造函数中调用基类的构造函数
运用super(参数列表)来显示的调用基类的构造函数

7.在面向对象程序设计中,协变返回类型指的是子类中的成员函数的返回值类型不必严格等同于父类中被重写的成员函数的返回值类型,而可以是更 “狭窄” 的类型。
Java 5.0添加了对协变返回类型的支持,即子类覆盖(即重写)基类方法时,返回的类型可以是基类方法返回类型的子类。协变返回类型允许返回更为具体的类型。

简单的说协变返回类型就是基类的方法可以返回指向基类的引用,按理来说派生类覆盖方法不能改变基类的返回类型,协变返回类型就允许我们将派生类返回类型变为指向派生类的返回类型。

8.java状态模式

例如:一个类派生出两个类,一个基类引用其中一个类,表现出一种形态,然后改变引用对象为另外一个派生类,则表现的行为也将变的不同。

9.java向上转型是安全的, 因为基类不可能大于派生类,而向下转型是危险的,因为派生类可能存在基类不存在的接口。


接口


1.包含抽象方法的类叫做抽象类,如果一个类包含一个或多个抽象方法,该类必须限定为抽象的。

2.java中除了抽象方法外,其他方法都必须定义,含有抽象方法的类是抽象基类,抽象基类不能实例化,只能作为接口,简单理解就是定义了一个规范。

3.interface关键字代替class表明这个类作为接口,implements表示继承这些接口,java中类只能继承一个类,c++中有多重继承(包括虚拟继承),但是java中可以继承多个接口。

4.friendly 就是默认访问权限(成员变量前面不加public protected 和 private)
重点看protected和fiendly两种权限的区别:对于protected成员变量,子孙类在任何地方都能访问(包内或者包外),但是对于friendly或者说默认成员变量,其实是不存在子孙类访问权限的概念的,就是说如果子孙类在包内,则可以访问,子孙类在包外则不可以访问。
protected在其子类中可以访问,无论是子类内部还是子类的实例,无论它们是在哪个包中,
但如果子类与父类不在同一个包中,在子类中用父类的实例去访问的话不可以
java 接口中所有成员的属性都为public static final,也就是说接口中声明的变量都是常量
c++ class默认访问权限为private

5.java接口默认权限为friendly,也就是包访问权限,如果在包外使用必须添加public

6.策略设计模式:创建一个能够根据所传递参数对象的不同而具有不同行为的方法

7.只要一个方法操作的是类而非接口,那么你就只能使用这个类及其子类,如果你想要将这个方法应用于不在此结构中的某个类,那么你就会触眉头了,接口可以在很大程度上放松这种限制,因此它可以使得我们编写复用性更好的代码

8.java代理和适配器(iterface)?

9.java中多重继承是继承多个接口,由于每个接口没有具体的实现,所以可以很容易的组合,但是c++多重继承就背负了很重的包袱。

10.java抽象类中可以有非抽象方法,如果是抽象方法在继承中必须要被实现。

11.接口可以作为类型,且继承该接口的可以转型。使用接口的核心原因之一:为了能够向上转型为多个基类型,第二个原因防止程序员创建该类对象。

12.抽象类和接口的选择
如果要创建不带任何方法定义和成员变量的基类,那么就应该选择接口,如果知道某个类会成为基类,优先选择成为接口。

13.继承任何一个类然后在实现接口,那么就是为这个类添加功能。

14.在Java语言中,接口可以嵌套在类或其它接口中。由于Java中interface内是不可以嵌套class的,所以接口的嵌套就共有两种方式:class嵌套interface、interface嵌套interface。
- 1. class嵌套interface
这时接口可以是public,private和package的。重点在private上,被定义为私有的接口只能在接口所在的类被实现。可以被实现为public的类也可以被实现为private的类。当被实现为public时,只能在被自身所在的类内部使用。只能够实现接口中的方法,在外部不能像正常类那样上传为接口类型。
- 2. interface嵌套interface

由于接口的元素必须是public的,所以被嵌套的接口自动就是public的,而不能定义成private的。在实现这种嵌套时,不必实现被嵌套的接口。

15.简单的java工厂模式,工厂生产物品,传递同一个接口的不同物品的工厂,从而产生不同的物品以及状态。

public class JavaFactory {    public  static void runCycle(CycleFactory cf){        Cycle cc = cf.getCycle();        cc.move();    }    public static void main(String[] args){        runCycle(new UnicycleFactory());        runCycle(new BicyleFactory());    }}interface Cycle{    void move();}interface CycleFactory{    Cycle getCycle();}class Unicycle implements Cycle{    @Override    public void move(){        System.out.println("Unicycle run");    }}class UnicycleFactory implements CycleFactory{    @Override    public Cycle getCycle(){        return new Unicycle();    }}class Bicyle implements Cycle{    @Override    public void move(){        System.out.println("Bicyle run");    }}class BicyleFactory implements CycleFactory{    @Override    public Cycle getCycle() {        return new Bicyle();    }}

16.恰当的原则应该是优先选择类而不是接口,从类开始,如果接口的必须性变得非常明确,那么就进行重构,接口是一种重要的工具,但是它们非常容易被滥用。


内部类


1.内部类有外部类的所有元素的访问权限(包括private),而c++嵌套类只是单纯的名字隐藏机制,与外围对象没有联系
内部类自动拥有外部类所有成员的访问权限,是因为当外部类对象创建一个内部类对象时,内部类对象就会秘密的捕获一个指向那个外部类对象的引用,使用时就通过引用。

2.必须使用外部类对象才能创建内部类,在拥有外部类对象之前是不可能创建内部类对象的,这是因为内部类会暗暗连接到外部类对象来创建内部类,如果你创建的是静态内部类,那么就不需要对外部类进行引用。
生成对外部类对象的引用,外部类名字加.加this

3.

public class JavaInner {    public static void main(String[] args) {        Outer o = new Outer();        Outer.Inner i = o.new Inner();        i.f();    }}class Outer{    static int i = 0;    class Inner{        void f(){            System.out.println("haha:" + i);        }    }}

4.将内部类向上转型为基类时,尤其是转型为一个接口的时候,内部类就有用了,基类内部函数返回创建一个内部类从而达到转型的目的

5.内部类分为成员内部类,局部内部类,静态内部类,匿名内部类。

局部内部类:局部内部类定义在方法里不能被private, public, protected修饰,这个方法可以是private,public,protected,它根据方法的权限来限定自己的权限,
局部内部类中不可定义静态变量,可以访问外部类的局部变量(即方法内的变量),但是变量必须是final的
在类外不可直接生成局部内部类(保证局部内部类对外是不可见的)。要想使用局部内部类时需要生成对象,对象调用方法,在方法中才能调用其局部内部类。通过内部类和接口达到一个强制的弱耦合,用局部内部类来实现接口,并在方法中返回接口类型,使局部内部类不可见,屏蔽实现类的可见性。

静态内部类:生成(new)一个静态内部类不需要外部类成员:这是静态内部类和成员内部类的区别。
而不需要通过生成外部类对象来生成。这样实际上使静态内部类成为了一个顶级类。静态内部类不可用private来进行定义
当类与接口(或者是接口与接口)发生方法命名冲突的时候,此时必须使用内部类来实现。用接口不能完全地实现多继承,用接口配合内部类才能实现真正的多继承。

匿名内部类:
1.一个类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的事先或是覆盖。
2.只是为了获得一个对象实例,不需要知道其实际类型。
3.类名没有意义,也就是不需要使用到。
一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类,没有类名,根据多态,我们使用其父类名。因他是局部内部类,那么局部内部类的所有限制都对其生效。匿名内部类是唯一一种无构造方法类。大部分匿名内部类是用于接口回调用的。匿名内部类在编译的时候由系统自动起名Out$1.class。如果一个对象编译时的类型是接口,那么其运行的类型为实现这个接口的类。因匿名内部类无构造方法,所以其使用范围非常的有限。当需要多个对象时使用局部内部类,因此局部内部类的应用相对比较多。匿名内部类中不能定义构造方法。如果一个对象编译时的类型是接口,那么其运行的类型为实现这个接口的类。

6.
内部类总结:

1.首先,把内部类作为外部类的一个特殊的成员来看待,因此它有类成员的封闭等级:private ,protected,默认(friendly),public
它有类成员的修饰符: static,final,abstract
2.非静态内部类nested inner class,内部类隐含有一个外部类的指针this,因此,它可以访问外部类的一切资源(当然包括private)
外部类访问内部类的成员,先要取得内部类的对象,并且取决于内部类成员的封装等级。
非静态内部类不能包含任何static成员.
3.静态内部类:static inner class,不再包含外部类的this指针,并且在外部类装载时初始化.
静态内部类能包含static或非static成员.
静态内部类只能访问外部类static成员.
外部类访问静态内部类的成员,循一般类法规。对于static成员,用类名.成员即可访问,对于非static成员,只能
用对象.成员进行访问
4.对于方法中的内部类或块中内部类只能访问块中或方法中的final变量。

类成员有两种static , non-static,同样内部类也有这两种
non-static 内部类的实例,必须在外部类的方法中创建或通过外部类的实例来创建(OuterClassInstanceName.new innerClassName(ConstructorParameter)),并且可直接访问外部类的信息,外部类对象可通过OuterClassName.this来引用
static 内部类的实例, 直接创建即可,没有对外部类实例的引用。
内部类不管static还是non-static都有对外部类的引用
non-static 内部类不允许有static成员

方法中的内部类只允许访问方法中的final局部变量和方法的final参数列表,所以说方法中的内部类和内部类没什麽区别。但方法中的内部类不能在方法以外访问,方法中不可以有static内部类
匿名内部类如果继承自接口,必须实现指定接口的方法,且无参数
匿名内部类如果继承自类,参数必须按父类的构造函数的参数传递

7.优先使用类而不是接口,如果你的设计中需要某个几口,你必须了解它, 否则不到迫不得已,不要将其放到你的设计中去。

8.普通类继承多个接口使用外部类继承和内部类继承没区别,如果是抽象类或具体的类,而不是接口,那就只能使用内部类才能实现多重继承。

9.java匿名内部类?

10.闭包
闭包是可以包含自由(未绑定)变量的代码块;这些变量不是在这个代码块或者任何全局上下文中定义的,而是在定义代码块的环境中定义。“闭包” 一词来源于以下两者的结合:要执行的代码块(由于自由变量的存在,相关变量引用没有释放)和为自由变量提供绑定的计算环境(作用域)。在 Scheme、Common Lisp、Smalltalk、Groovy、JavaScript、Ruby 和 Python 等语言中都能找到对闭包不同程度的支持。

闭包的价值在于可以作为函数对象 或者匿名函数,对于类型系统而言这就意味着不仅要表示数据还要表示代码。支持闭包的多数语言都将函数作为第一级对象,就是说这些函数可以存储到变量中、作为参数传递给其他函数,最重要的是能够被函数动态地创建和返回。

java回调的价值在于它的灵活性,可以在运行时动态决定需要调用什么方法。也就是闭包中的根据环境变量来变化。

如果是直接简答的继承是不具有这样的灵活性的。

11.内部类把变化的事物和不变化的事物分离开来。

12.内部类的继承,内部类的构造器必须连接到指向其外部类对象的引用,所以在继承内部类的时候,指向外围类对象的“秘密的”引用必须被初始化,而在派生类中不再存在可连接的默认对象。

所以要生成一个构造器时,必须使用enclosingclassreference.super( )才可以。

外部类内部包含内部类只是声明而已,如果我们要使用必须实例化内部类,在外部类定义多个内部类可以使外部类表现出多种不同的样子,类似闭包把

13.内部类可以被覆盖吗

当继承了某个外部类的时候,内部类并没有发生什么特别变化,这两个内部类是完全独立的实体,各自在自己的命名空间内。

14.局部内部类的名字在方法外是不可见的,那么我们有时使用局部内部类的理由是我们需要一个已命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例初始化,另一个理由就是需要不止一个该内部类的对象。

15.内部类也必须产生一个.class文件,一般是外部类$内部类.class,如果内部类是匿名的,编译器会简单的产生一个数字作为其标识。


异常


1.异常参数
我们总是在堆上创建异常对象,也伴随着存储空间和构造器的调用。所有的标准异常都有两个构造器,默认和带字符串参数的。我们也可以通过继承异常基类来自己创造异常类

2.super()表示调用基类的构造器

3.异常和日志记录 thinking in java P253

4.异常说明,属于方法声明的一部分,紧跟在形式参数列表之后,关键字,throws,鼓励我们列出可能抛出的异常。

5.抛出异常后会跳转到catch代码块继续执行,
正常执行的代码如果出现异常,就不会执行出现异常语句后面的所有正常代码.
异常可能会被捕获掉,比如上面catch声明的是捕获Exception,那么所有Exception包括子类都会被捕获,但如Error或者是Throwable但又不是Exception(Exception继承Throwable)就不会被捕获.
如果异常被捕获,就会执行catch里面的代码.如果异常没有被捕获,就会往外抛出,相当于这整个方法出现了异常.
finally中的代码只要执行进了try catch永远都会被执行.执行完finally中的代码,如果异常被捕获就会执行外面跟这个try catch无关的代码.否则就会继续往外抛出异常.
return无论在哪里,只要执行到就会返回,但唯一一点不同的是如果return在try或者catch中,即使返回了,最终finally中的代码都会被执行.这种情况最常用的是打开了某些资源后必须关闭,比如打开了一个OutputStream,那就应该在finally中关闭,这样无论有没有出现异常,都会被关闭.

6.想要在捕获一个异常以后抛出另外一个异常,并且依旧保存旧异常的信息叫做异常链

7.使用finally的情况,已经打开的文件或网络连接等等。

8.当覆盖方法的时候,只能抛出在基类方法的异常说明列出的那些异常。

9.在构造器中抛出异常,通过finally不能解决问题,因为finally是清楚构造完的对象,构造器抛出异常可能是构造了一半的对象。
解决:对于可能构造失败的对象,我们使用try-catch嵌套,在try的内部try来执行关闭销毁操作,确保是在对象构造完毕的情况下销毁。
简单来说就是,在创建需要清理的对象之后,立即进入一个try-finally语句块。
我们还需要判断此对象的构造可不可能失败

10.异常匹配
抛出异常的时候,异常处理系统会按照最近的catch进行匹配,要注意派生类对象也可以撇皮基类的处理程序,但是派生类处理程序不能放在基类的处理程序之前,因为这样基类会永远得不到执行会报错。

11.和java不同,c++不会在编译时进行检查以确定函数或方法是不是真的抛出异常,或者异常说明是不是完整,这样的检查只发生在运行期间,如果抛出的异常与异常说明不符,c++会调用标准库的unexpected函数。

12.运行时系统从发生异常的方法开始,依次回查调用栈中的方法,直至找到含有合适异常处理器的方法并执行。当运行时系统遍历调用栈而未找到合适 的异常处理器,则运行时系统终止。同时,意味着Java程序的终止。
也就是抛出异常,如果当层不能捕获继续向上层抛出,但是需要注意try后面必须跟一个catch或多喝catch块,如果不很catch块就必须根一个finally块。

13.java什么情况下必须用throws抛出异常?
答:在程序中抛出了非RuntimeException异常却没有对其处理(用try catch块处理)的情况下,必须在方法头throws该异常。

14.
try 块:用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。

try语句块中,出现异常之后的语句也不会被执行,catch语句块执行完后,执行finally语句块里的语句,最后执行finally语句块后的语句

catch 块:用于处理try捕获到的异常。
finally 块:无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行。在以下4种特殊情况下,finally块不会被执行:
1)在finally语句块中发生了异常。
2)在前面的代码中用了System.exit()退出程序。
3)程序所在的线程死亡。
4)关闭CPU。

15.
如果一个方法可能会出现异常,但没有能力处理这种异常,可以在方法声明处用throws子句来声明抛出异常。例如汽车在运行时可能会出现故障,汽车本身没办法处理这个故障,那就让开车的人来处理。

 throws语句用在方法定义时声明该方法要抛出的异常类型,如果抛出的是Exception异常类型,则该方法被声明为抛出所有的异常。多个异常可使用逗号分割。

Throws抛出异常的规则:

1) 如果是不可查异常(unchecked exception),即Error、RuntimeException或它们的子类,那么可以不使用throws关键字来声明要抛出的异常,编译仍能顺利通过,但在运行时会被系统抛出。

2)必须声明方法可抛出的任何可查异常(checked exception)。即如果一个方法可能出现受可查异常,要么用try-catch语句捕获,要么用throws子句声明将它抛出,否则会导致编译错误

3)仅当抛出了异常,该方法的调用者才必须处理或者重新抛出该异常。当方法的调用者无力处理该异常的时候,应该继续抛出,而不是囫囵吞枣。

4)调用方法必须遵循任何可查异常的处理和声明规则。若覆盖一个方法,则不能声明与覆盖方法不同的异常。声明的任何异常必须是被覆盖方法所声明异常的同类或子类。

throw 抛出的只能够是可抛出类Throwable 或者其子类的实例对象

0 0
原创粉丝点击