继承可以理解为现实世界中的“是一种(is-a)”关系。实现继承是通过extends关键字在声明类的时候指定其父类:[修饰符] class 类名 extends 父类名
继承某个父类而生产新的子类不但拥有父类的变量与方法,还可以为子类添加新的成员变量和成员方法,以增强父类的功能,也就是所谓的扩展,甚至还可以在子类中为父类的某个方法定义多个重载方法,增加该类的灵活性。
子类可以重写父类的某个方法或者说是覆盖父类的某个方法。只要在子类中定义与父类相同的方法即可。还可以使用super关键字引用父类的方法,然后再添加新的业务代码。还可以在子类的构造方法中使用super关键字执行父类的构造方法:super([构造参数列表])
Java中定义了private、public、protected和默认的权限修饰符,这些修饰符控制着对类和类的成员变量以及成员方法的访问规则。另外还可以辅助static和final关键字定义特殊规则。
访问包位置 | 类 | 修 | 饰 | 符 |
---|---|---|---|---|
修饰符 | private | protected | 默认修饰符 | public |
本类 | 可见 | 可见 | 可见 | 可见 |
同包其他类 | 不可见 | 可见 | 可见 | 可见 |
其他包的类 | 不可见 | 不可见 | 不可见 | 可见 |
同包的子类 | 不可见 | 可见 | 可见 | 可见 |
其他包的子类 | 不可见 | 可见 | 不可见 | 可见 |
使用public修饰的类、成员变量和成员方法,其他类都可以访问,包括任意包中的任意类以及子类。
private是私有权限修饰符,它只有本类能够访问,对于其他方式的访问都会拒绝。
protected是保护级别的权限修饰符,它保护成员不会被其他包或非子类访问。
当不添加任何权限修饰符时,编译器会使用默认的修饰符,其权限级别与protected类似,不同之处在于其他包定义的子类无法访问父类默认权限修饰的成员。
封装是指把对象的属性隐藏在对象的内部,不允许外部直接访问和修改。Java规范中的设置器与访问器就是实现封装的标准方法,它们用于获取和设置对象的属性值。
要实现封装,第一步就是设置类的成员变量(即对象的属性)使用private修饰符,使其他类无法直接访问该成员变量,以防止外部直接访问和修改。把成员变量设置为private私有权限之后,其他类就不能访问了,必须通过本类定义的设置器方法来设置和修改该成员变量的值。设置器方法的命名一般以set作为前缀,以属性名作为后缀。对于设置器来说,他需要暴露给其他类使其可以访问,故使用public修饰符。方法体中区别参数与成员变量使用了this关键字引用成员变量,并赋值为参数的值,也可以使用与成员变量不同名称的参数。要使用访问器方法读取对象的属性值。访问器以get或is作为方法名称的前缀,以属性名作为后缀。对于boolean类型的属性,应该使用is前缀定义访问器方法。
在Eclipse中按“Shift+Alt+S”,R快捷键,弹出“生成Getter和Setter”对话框,这个对话框就是生成访问器与设置器的向导。
在Java中,所有的类都直接或间接继承了java.lang.Object类。Object类是比较特殊的类,它是所有类的父类,也就是说Java语言中任何一个类都是Object类的子类。当创建一个类时,如果没有使用extends关键字继承指定的类,那么编译器总是默认直接继承Object类,如果指定继承其他类,那么也会间接继承Object类。
Object类中主要包括clone()、finalize()、equals()、toString()等方法。其中,常用的两个方法为equals()和toString()方法。由于所有的类都是Object类的子类,所以任何类都可以重写Object类中的方法。
注意:Object类中的getClass()、notify()、notifyAll()、wait()等方法不能被重写,因为这些方法被定义为final类型。
equals()方法是在Object类中定义的,用于判断两个对象是否为相同的方法,大部分子类都重写了该方法,用于比较指定类型的对象。如果Object的子类没有重写equals()方法,该方法将默认使用“==”运算符判断两个对象。
Object类中的toString()方法的功能是将一个对象转换为字符串形式,当一个对象参与字符串的“+”连接符操作时,也会调用该方法把对象转换从字符串,然后再和另一个字符串操作数连接。toString()方法会返回一个String()实例,在实际应用中通常重写toString()方法,为对象提供一个特定的输出模式。当这个类转换为字符串或与字符串连接时,将自动调用重写的toString()方法。
在执行类型转型时,如果把对象转换成错误的类型时,就会发生ClassCastException异常,所以在执行类型转型之前需要先判断对象的类型,防止程序出现错误。Java使用instanceof操作符来完成对象类型的判断。使用instanceof操作符可以判断对象是不是指定的类或子类的实例对象,或者接口的实现类对象:obj instanceof Class;返回值为布尔值,true或false。一个对象即是创建给对象的类的实例,也是父类的实例。所以它们可以强制类型转换成父类的类型或者把子类对象赋值给父类的对象变量。这种子类对象赋值给父类引用的形式称为向上转型,它将导致声明的对象只能调用父类的方法。因为父类中没有定义子类的新方法,它只包含定义父类时的方法。
任何对象使用instanceOf关键字和Object类进行判断,返回的结果一定是true。可以使用Object类型的变量来传递未知类型的对象。在判断对象的类型之后,使用强制类型转换把对象转换为原来的类型,就可以调用需要的方法,这种父类对象转换为子类对象的形式称为向下转型。向下转型一定要先确定对象的类型是否和要转换的类型有继承关系,否则会出现错误。
多态是指程序中同一操作在不同环境中有不同的语义解释。向上转型可以声明父类的引用变量,但是赋值为子类的实例对象。也就是说,对象变量的声明与赋值可以不是一个类型。通过使用父类类型的引用,可以定义多态数组或多态方法等。
多态数组就是数组使用父类声明,而数组中的元素都是子类的实例对象,它们有父类同名的方法,但是方法体却可以不一样。
方法的参数也可以多态,方法的返回类型也可以多态。
Java语言中抽象类不可以实例化对象。
使用abstract关键字定义的类称为抽象类,而使用这个关键字定义的方法称为抽象方法,抽象方法没有方法体,这个方法本身没有任何意义,除非它被重写,而承载这个抽象方法的抽象类就必须被继承,实际上抽象类除了被继承之外没有任何意义。如果声明一个抽象的方法,就必须将承载这个抽象方法的类定义为抽象,不可能在非抽象类中定义抽象方法,即只要类中有一个抽象方法,则此类就必须标记为抽象类。抽象类被继承后必须重写抽象类中所有的抽象方法,并定义方法体,否则编译无法通过。
java语言规定类不能同时继承多个父类,也就是java只支持单继承。
接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。接口使用interface关键字进行定义。一个类实现一个接口可以使用implements关键字。
在接口中定义的方法必须被定义为public或abstract修饰符,其他修饰权限不被Java编译器所认可。如果不将该方法声明为public形式,它的默认修饰符也是public。在接口中定义的任何成员变量默认都是static和final的。
接口是否可以向上转型?在Java中无论是将一个类向上转型为父类对象,还是向上转型为抽象父类对象,还是向上转型为该类实现接口,都没有问题。
一个类可以同时实现多个接口,可以将所有需要继承的接口放置在implements关键字后使用逗号隔开。另外接口之间也可以继承。
Singleton单例模式,用于创建一个全局共享的实例对象。实现原理就是将类的构造方法私有化,也就是使用private修饰符来修饰构造方法,这样外部就不能使用构造方法创建对象了,但是在本类内部还是可以创建对象的,所以,可以创建一个本类类型的成员变量来保存本类的唯一对象,然后提供属性访问器方法获取这个唯一的实例,但是每次获取的都是同一个对象,而不是重新创建的。
两个基本数据类型的数值可以直接使用“==”判断是否相等,但是两个对象是存放在不同内存空间的两个数据结构,要判断它们是不能使用“==”操作符的,那样只会对比两个对象所引用的内存地址,而不是对象内容。判断两个对象的内容是否相同,必须使用equals()方法。
final关键字在Java语言中用于修饰最终类型的类和成员。被final修饰后,通常不能再改变内容。final除了可以修饰基本数据类型的常量以外,还可以修饰对象引用变量,由于数组变量也可以被看作一个对象引用,所以final可修饰数组。一旦一个对象引用被修饰为final后,它只能恒定指向一个对象,无法将其改变指向另一个对象。一个既是static又是final的字段只占据一段不能改变的存储空间。可以将方法的参数定义为final类型,这预示着无法在方法体中更改参数值或更改参数所指向的对象引用。
定义为final的方法不能被重写。定义为final的方法执行效率要高于非final方法。一个定义为private的方法隐式地被指定为final类型。定义为final的类不能被继承,类中的所有方法都被隐式地设置为final形式,但是final类中的成员变量可以被定义为final或非final形式。
其他类中再定义的类称为内部类,内部类可以分为成员内部类、局部内部类以及匿名类等。
在一个类的内部类中可以直接存取其所在类的私有成员变量。在内部类中可以随意使用外部类的成员方法以及成员变量,不论这些类成员被修饰为private。
内部类的实例一定要绑定在外部类的实例上,如果从外部类中初始化一个内部类对象,那么内部类对象就会绑定在外部类对象上。内部类初始化方式与其他类初始化方式相同,都是使用new关键字。实例的外部类创建内部类实例时,与其他类创建对象相同。内部类可以访问它的外部类的成员,但内部类的成员只有在内部类的范围内是可知的,不能被外部类使用。如果在外部类和非静态方法之外实例化内部类对象时,需要使用外部类、内部类的形式指定该对象的类型。在主方法中或其他类中实例化本实例的内部类对象,必须在new操作符之前提供一个外部类的引用。
在实例化内部类对象时,不能在new操作符之前使用外部类名称那种形式进行实例化内部类对象,而应该使用外部类的对象来创建其内部类的对象。内部类对象会依赖于外部类对象,除非已经存在一个外部类对象,否则不能创建内部类对象。另外非内部类不能被声明为private或protected访问类型。
如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字。即使用外部类名称后跟一个点操作符和this关键字便可获得外部类的一个引用。
内部类不仅可以在类中进行定义,在类的局部位置也可以定义内部类。在方法中定义的内部类只能访问方法中的final类型的局部变量,因为在方法中定义的局部变量相当于一个常量,它的生命周期超出方法运行的生命周期,由于该局部变量被设置为final,所以不能在内部类中改变该局部变量的值。
在内部类前添加static修饰符,这个内部类就变成了静态内部类。一个静态内部类中可以声明static成员,但在非静态内部类中不可以声明静态成员,静态内部类的最大一个特点就是不可以使用外部类的非静态成员。静态内部类的两个特点:如果创建静态内部类的对象,不需要外部类对象的引用;不能从静态内部类的对象中访问非静态外部类的对象。
异常是一个在程序执行期间发生的事件,它中断了正在执行的程序的正常指定过程。异常在Java语言中也是对象。当在某一方法中发生异常错误的时候,这个方法创建一个对象,并且把它传递给运行时的系统。这个对象就是异常对象。
java语言可以捕获程序中可能出现的异常,这主要由try...catch语句完成。try语句块存放的是可能发生异常的Java语句。catch程序块在try语句块之后,用来处理被捕获的异常。另外finally语句块是异常处理结构的最后执行部分,不管try块中代码如何退出,都将执行finally块。finally是可选部分。
java的异常处理是结构化的:当try代码块中语句发生了异常,程序就会调转到catch代码块中执行,执行完catch代码块中的程序代码后,继续执行catch代码块后的其他代码,不会执行try代码块中发生异常语句后面的代码。
catch关键字后面括号中的参数类型Exception就是try代码块传递给catch代码块的异常类型。catch代码块中的语句“e.printStackTrace();”用于输出异常的堆栈跟踪信息。通常异常对象常用的3个方法如下:getMessage()函数:获取异常信息;toString()函数:将异常对象转换为字符串,其中包括异常类型与错误信息;printStackTrace()函数:指出异常的类型、性质、栈层次及出现在程序中的位置。
完整的异常处理语句一般都包含finally语句。最好在catch代码块中有处理异常的代码。在3种特殊情况下,finally块不会被执行:在finally语句块中发生了异常;在前面的代码中用来System.exit()退出程序;程序所在的线程死亡。
若某个方法可能会发生异常,但不想在当前方法中处理这个异常,那么可以使用throws关键字将异常向上抛出,由调用者处理异常。另外,throws关键字可以在方法中抛出异常。
throws关键字在方法声明的最后,方法体中可能出现异常,并将这些异常向上抛出给方法的调用者处理。多个异常使用逗号分割。使用throws关键字将异常抛给上一次方法调用者后,如果不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的代码。如果是Error、RuntimeException或它们的子类,那么可以不使用throws关键字来声明要抛出的异常。编译仍能顺利通过,但在运行时会被系统抛出。
throws关键字通常用于方法体中,它用于有意的异常抛出。程序在执行到throws语句时,立即终止,它后面的语句都不执行,除非调用者捕获并处理了该异常。throws通常用来抛出用户自定义异常,而自定义异常都是通过基础Exception类实现的。该类是所有可捕获异常的父类。try...catch语句中,多个catch的顺序一定要遵循子类在上父类在下的规则。
RuntimeException异常是程序运行过程中产生的异常。所有的异常类都是Throwable类的子类。Throwable类派生了两个子类,分别是Exception和Error类。Error类及其子类用来描述Java运行系统的内部错误以及资源耗尽的错误,这类错误比较严重。Exception类称为非致命性类,可以通过捕捉处理使程序继续执行。Exception类根据错误发生的原因分为RuntimeException异常和RuntimeException之处的异常。
RuntimeException异常的种类 | 说明 |
---|---|
NullPointerException | 空指针异常类 |
ArrayIndexOutOfBoundsException | 数组下标越界异常 |
ArithmeticException | 算术异常类 |
ArrayStoreException | 数组中包含不兼容的值抛出的异常 |
IllegalArgumentException | 非法参数异常 |
SecurityException | 安全性异常 |
NegativeArraySizeException | 数组长度为负异常 |
异常处理的主要作用是捕获程序在运行时发生的异常并进行相应的处理。
异常处理可遵循的原则:在当前方法声明中使用try-catch语句捕获异常;一个方法被重写时,重写它的方法必须抛出相同的异常或异常的子类;如果父类方法抛出多个异常,那么子类重写该方法必须抛出那些异常的一个子集。不能抛出新异常。