1.类的继承
类的基本思想就是基于某个父类进行扩展,得到一个 新的子类。
子类可以继承父类原有的属性和方法
可以增加原来父类所不具备的属性和方法
或者直接重写父类中的某些方法
Java中使用extends关键字来标识两个类的继承关系
class Test {
public Test(){//构造方法
//SomeSentence
}
protected void doSomething(){//成员方法
//SomeSentence
}
protected Test dolt(){
return new Test(); //返回值类型为Test类型
}
}
classTested extends Test{ //继承父类
public Test2(){ //构造方法
super(); //调用父类构造方法
super.doSomething();//调用父类成员方法
}
public void doSomething(){//新增方法
//SomeStentence
}
public void doSomething(){//重写父类方法
//SomeSentence
}
protected void Test2 dolt(){重写父类方法,方法返回值类型为Test2类型
return new Test2();
}
}
super的作用主要在下面三种情况下:
1、调用父类被子类重写的方法;
2、调用父类被子类重定义的字段(被隐藏的成员变量);
3、调用父类的构造方法;`
关于super()详见该贴:https://blog.csdn.net/shakespeare001/article/details/51388516.
子类没有权限调用父类中被修饰为private的方法,只可以调用父类中修饰为public或protected 的成员方法。
继承并不只是扩展父类的功能,还可以重写父类的成员方法。
重写就是在子类中将父类的成员方法的名称保留,重写成员方法的实现内容,更改成员方法的存储权限,或是修改成员方法的返回值类型。
重构:子类与父类的成员方法返回值、方法名 称、参数类型及个数完全相同,唯一不同的是方法实现内容。(特殊的重写)
修改方法的修饰权限只能从小的范围到大的范围改变。
子类重写父类的方法,若修改方法的返回值类型时,则重写的返回值类型必须是父类中同一方法返回值类型的子类。
在子类的构造方法 中自动调用父类的无参构造方法。如下:
class Parent{
Parent(){
System.out.println("调用父类的Parent()构造方法");
}
}
class SubParent extends Parent{
SubParent(){
System.out.println("调用子类的SubParent()构造方法");
}
public static class Subroutine extends SubParent{
Subroutine(){
System.out.println("调用子类的Subroutine()构造方法");
}
}
public static void main(String[] args){
Subroutine s=new Subroutine();
}
}
调用父类的Parent()构造方法
调用子类的SubParent()构造方法
调用子类的Subroutine()构造方法
上述结果表明:,实例化子类对象时首先要实例化父类对象,然后再实例化子类对象,所以在子 类构造方法访问父类的构造方法之前,父类已经完成实例化操作。
当声明类时不使用public、protected和private时这个类预设为包存取范围,即只有一个包中的类可以调用这个类的成员变量或成员方法
2.object类
Object类是比较特殊的类, 它是所有类的父类,是Java类层中的最高层类。
Object类中的getClass()、notify()、notifyAll()、wait()等方法不能被重 写,因为这些方法被定义为final类型.
Object类中的几个重要方法
a. getClass()方法
getClass()方法是Object类定义的方法,它会返回对象执行时的Class实例,然后使用此实例调用getName()方法可以取得类的名称。
getClass().getname();
b.toString()方法
toString()方法的功能是将一个对象返回为字符串形式,它会返回一个String 实例。
public class ObjectInstance{
public String toString(){
return "在"+getClass().getName()+"类中重写同toString()方法";
}
public static void main(String[] args){
System.out.println(new ObjectInstance());
}
}
在ObjectInstance类中重写同toString()方法
c.equals()方法
“==”比较的是两个对象的引用是否相等
equals()方法比较 的是两个对象的实际内容
class V{ //自定义类V
}
public class OverWriteEquals{
public static void main(String[] args){
String s1="123";//实例化两个对象,内容相同
String s2="123";
System.out.println(s1.equals(s2));
V v1=new V();//实例化两个V类对象
V v2=new V();
System.out.println(v1.equals(v2));
}
}
true
false
因为equals()方法的默认实现是使用“==”运算符比较两个对象的引用地址,而不是比较对象的内容,所以要想真正做到比较两个对象的内容,需要在自定义类中重写equals()方法。
重写实例如下如下:
String str1=new String("123");
String str2=new String("123");
System.out.println(str1.equals(str2));
3.对象类型转换
对象类型的转换主要包括向上转型与向下转型操作
平行四边形类的主方法中调用draw()时给予的参数类型却是Parallelogram(平行四边形类)类型的。平行四边形也是一种类型的四边形,所以可以将平行四边形 类的对象看作是一个四边形类的对象,相当于“Quadrangle obj = new Parallelogram();”就是把子类对象赋值给父类类型的变量,这种技术被称为“向上转型”。向上转型是从一个较具体的类到较抽象的类的转换,所以它总是安全的。
向下转型是将较抽象的类转换为较具体的类,这样的转型通常会出现问题。子类对象总是父类的一个实例,但父类对象不一定是子类的实例。
class Quadrangle{
public static void draw (Quadrangle q){
//SomeSentence
}
}
class Parallelogram extends Quadrangle{
public static void main(String[] args){
draw(new Parallelogram());
//将平行四边形类对象看作四边形对象,称为向上转型
Quadrangle q=new Parallelogram();
//Parallelogram p = q;
//将父类对象赋予子类对象,这种写法是错误的
//将父类对象赋予子类对象,并强制转为子类型,这种写法是对的
Parallelogram p=(Parallelogram)q;
}
}
在做向下转型操作时,将特性范围小的对象转换为特性范围大的 对象肯定会出现问题,
将父类对象强制转换为某个子类对象,这种方式称为显式类型转换
在程序中使用向下转型技术时,必须使用显式类型转换,向编译器指明要将父类对象转换为哪一种类型的子类对象。
4.instanceof操作符
instanceof操作也可以判断是否一个类实现了某个接口,也可以用它来判断一个实例对象是否属于一个类。
在执行向下转型之前需要养成一个良好的习 惯,就是判断父类对象是否为子类对象的实例。通常使用instanceof操作符来完成
instanceof的语法格式如下:
myobject instanceof ExampleClass
myobject:某类的对象引用。
ExampleClass:某个类。 instanceof操作符的返回值为布尔值,返回值为true,说明myobject对象为ExampleClass的实例对象,反之不是。
instanceof是Java语言的关键字,在Java语言中的关键字都为小写。
实例:
class Quadrangle{
public static void draw(Quadrangle q){
//SomeSentence
}
}
class Square extends Quadrangle {
//SomeSentence
}
class Anything{
//SomeSentece
}
class Parallelogram extends Quadrangle{
public static void main(String[] args){
Quadrangle q=new Quadrangle ();//实例化父对象
//判断父类对象是否为Parallelogram子类的一个实例
if(q instanceof Parallelogram){
Parallelogram p=(Parallelogram)q;//向下转型操作
}
//判断父类对象是否为Square子类的一个实例
if(q instanceof Square){
Square s=(Square)q;//进行向下转型操作
}
//由于q对象部位Anything类的对象,所以这条语句是错误的
//System.out.println(q);instanceofAnything
}
}
5.方法的重载
方法的重载就是在同一个类中允许存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可。
实例:
public class OverLoadTest {
public static int add(int a,int b){
return a+b;
}
//定义与第一个方法名字相同,参数类型不同的方法
public static double add(double a,double b){
return a+b;
}
public static int add(int a){
return a;
}
public static int add(int a,double b){
return 1;
}
public static int add(double b,int a){
return 1;
}
public static void main(String[] args){
System.out.println("调用add(int,int)方法"+add(1,2));
System.out.println("调用add(double,double)方法"+add(2.1,3.3));
System.out.println("调用add(int)方法"+add(1));
}
}
调用add(int,int)方法3
调用add(double,double)方法5.4
调用add(int)方法1
重载的判断
前两个方法的参数类型不同,并且方法的返回值类型也不同,所以这两个方法构成重载关系(返回值不同不足以区分两个方法的重载)
第3个方法的参数个数少于前两个方法,所以这3个方法也构成了重载关系
最后两个方法相比,发现除了参数的出现顺序不同之外,其他都相同,同样构成了重载关系
编译器是利用方法名、方法各参数类型和参数的个数以及参数的顺序来确定类中的方法是否唯一。
public static int add(int... a) {
int s = 0;
for (int i = 0; i < a.length; i++)
s += a[i];
return s;
}
该方法为不定长参数方法。语法如下:
返回值方法名(参数数据类型…参数名称)
参数列表中使用“…”形式定义不定长参数,其实这个不定长参数a就是一个数组,编译器会将**(int…a)这种形式看作是(int[]a)**
定义不定长参数依然可以作为add()方法的重载方法, 由于它的参数是不定长的,所以满足根据参数个数区分重载的条件。
6.抽象类与接口
一般将父类定义为抽象类,需要使用这个父类进行继承与 多态处理。在多态机制中,并不需要将父类初始化对象,我们需要的只是子类对象,所以在Java语言中设置抽象类不可以实例化对象。
抽象类的语法:
public adstract class Test{
abstract void testAbstract();//定义抽象方法
}
abstract为定义抽象类的关键字。
使用abstract关键字定义的类称为抽象类,而使用这个关键字定义的方法称为抽象方法。抽象方法没有方法体,这个方法本身没有任何意义,除非它被重写。(实际上抽象类除了被继承之外没有任何意 义)
声明一个抽象的方法,就必须将承载这个抽象方法的类定义为抽象类,不可能在非抽象类中获取抽象方法。
只要类中有一个抽象方 法,此类就被标记为抽象类。
抽象类被继承后需要实现其中所有的抽象方法,也就是保证相同的方法名称、 参数列表和相同返回值类型创建出非抽象方法,当然也可以是抽象方法。
接口:接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体
public interface drawTest{
void draw();//接口内的方法,省略abstract关键字
}
public:接口可以像类一样被权限修饰符修饰,但public关键字仅限用于 接口在与其同名的文件中被定义。
interface:定义接口关键字。
drawTest:接口名称
一个类实现一个接口,可以使用implements关键字,
public class Parallelogram extends Quadrangle implements drawTest{
...//
}
在接口中,方法必须被定义为public或abstract形式,其他修饰权限不被Java 编译器认可。
在接口中定义的任何字段都自动是static和final的
接口与继承
Java中不允许出现多重继承,但使用接口就可以实现多重继承。一个类可以同 时实现多个接口,因此可以将所有需要继承的接口放置在implements关键字后并使用逗号隔开.
class 类名 implements 接口1,接口2,…,接口n
在定义一个接口时,使该接口继承另外一个接口
interface intf1{
}
inetrface intf2 extends intf1{
}