java
和某些面向对象语言(如 c++)在实现继承的不同之处在于java只支持单继承,不支持多重继承。即java中一个类只能继承于另一个类。我们将被继承的类称之为父类(基类),继承类称之为子类(派生类)。在java中用关键字extends来实现单继承。在前面所讲已知,实现继承关系的类之间有着必然的联系,不能将不相关的类实现继承,就象人类不能继承于鸟类!
那怎么去判断类和类之间是否有着必然联系呢?实际上,前面我们已知当某类A和类 B之间有着共同的属性和行为时,那么类A和类
B之间就可能是继承关系或者有着共同的父类。继承带来了三个好处:减少代码冗余;维护变得简单;扩展变得容易。构造方法不能被继承!一个类得到构造构造方法只有两种途径:自定义构造方法;使用JVM分配的缺省构造方法。但是,可以在子类中访问父类的构造方法,后面我们会深入。
在java中是通过各种访问限定符来实现数据封装的,共分为四种访问级别(由高到低):private(私有)、friendly(缺省)、protected(受保护)、public(公共)。注意:以上四种访问修饰符可以作用于任何变量和方法,类只可以定义为默认或公共级别(嵌套类除外)。
public(公共) :当变量或方法被public修饰时,该变量和方法可以在任何地方(指的是任何包中)的任何类中被访问;
protected(受保护的) :当类的变量或方法被 protected修饰时,该变量和方法只可以在同包中的任何类、不同包中的任何当前类的子类中所访问。即不同包中的任何不是该类的子类不可访问级别为protected的变量和方法。
friendly(缺省的) :当类的变量和方法没有显式地被任何访问区分符修饰时,该变量和方法的访问级别是缺省的。缺省的变量和方法只能在同包的类中访问。
private(私有的) :被 private所修饰的所有变量和方法只能在所属类中被访问。即类的私有成员和变量只能在当前类中被访问。
对于java
编译器来说,它只依据方法的名称、参数列表的不同来判断两个方法是否相同,如果出现两个名称相同、参数也完全一致的方法,那么编译器就认为这两个方法是完全一样的,也就是说方法被重复定义!
通过重载,可以在一个类中定义相同名称、不同参数的实现相同功能的多个方法,这样就避免了给每个方法取不同名称、熟记每个不同名的方法对应的功能的额外工作量,提高了我们的开发效率。当一个类中的多个同名方法满足以下条件时之一时,即实现了方法重载:
a. 不同的参数个数
b. 不同的参数类型
c. 不同的参数顺序
如果有一个类带有几个构造函数,那么也许会想复制其中一个构造函数的某些功能到另一个构造函数中。可以通过使用关键字this作为一个方法调用来达到这个目的。对于this的任何调用,如果出现,在任何构造函数中必须是第一个语句。构造函数中调用另一构造函数,其调用(this()、super())有且只能有一次,并不能同时出现调用。
1this与 super
1.1this 的使用场合
在方法内借助 this来明确表示引用的是类的数据成员,而不是形参或局部变量,从而提高程序的可读性。
简单地说,this代表了当前对象的一个引用,可将其理解为对象的另一个名字,通过这个名字可以顺利地访问对象、修改对象的数据成员、调用对象的方法。
this 的使用场合主要有以下三种:
1)用来访问当前对象的数据成员:
this.数据成员
2)用来访问当前对象的成员方法:
this.成员方法(参数)
3)当有重载的构造方法时,用来引用同类的其他构造方法:
this(参数)
1.2super 的使用场合
super 表示的是当前对象的直接父类对象,是当前对象的直接父类对象的引用。
所谓直接父类是相对于当前对象的其他“祖先”类而言。
若子类的数据成员或成员方法名与父类的数据成员或成员方法名相同时,当要调用父类的同名方法或使用父类的同名数据成员,则可用关键字 super来指明父类的数据成员和方法。
super 的使用场合有三种:
1)用来访问直接父类隐藏的数据成员:
super.数据成员
2)用来调用直接父类中被覆盖的成员方法:
super.成员方法(参数)
3)用来调用直接父类的构造方法:
super(参数)
2. 构造方法的重载与继承
2.1 构造方法的重载
一个类的若干个构造方法之间可以相互调用。
当一个构造方法需要调用另一个构造方法时,可以使用关键字 this,同时这个调用语句应该是整个构造方法的第一个可执行语句。
使用关键字 this来调用同类的其他构造函数时,优点同样是可以最大限度地提高对已有代码的利用程度,提高程序的抽象度和封装性,减少程序的维护工作量。
2.2 构造方法的继承
子类可以继承父类的构造方法,构造方法的继承遵循以下的原则:
子类无条件地继承父类的不含参数的构造方法。
如果子类自己没有构造方法,则它将继承父类的无参数构造方法作为自己的构造方法;如果子类自己定义了构造方法,则在创建新对象时,它将先执行继承自父类的无参数构造方法,然后再执行自己的构造方法。
对于父类含参数的构造方法,子类可以通过在自己的构造方法中使用 super关键字来调用它,但这个调用语句必须是子类构造方法的第一个可执行语句。
覆盖是基于继承的,没有继承就没有覆盖。在 java中,覆盖的实现是在子类中对从父类中继承过来的非私有方法的内容进行修改或扩展的一个动作(注意:不能违反访问级别的限制,即子类方法的访问级别不能低于父类方法的访问级别)。
实现方法的覆盖必须满足以下所有条件:
a. 覆盖方法的方法签名(方法名,参数,返回类型)必须与被覆盖方法的方法签名相同
b. 覆盖方法的访问级别不能比被覆盖方法访问级别低
c. 覆盖方法不能比它所覆盖的方法抛出更多的异常。
在 java中的多态就体现在一个变量可以引用多个不同类对象,前提是这些不同类必须有者共同的父类,从而该变量可以且只能调用每个不同对象之间的公共操作集(方法)。父类引用可以引用子类对象,同时该父类引用只能访问所有子类的公有操作集(从父类继承过来的成员);当子类中已覆盖继承方法时,父类变量调用的将是子类中的已覆盖方法!
Extends Object是JVM自动给任意类加上去的,从而保证 java中的所有类都具备一个通用父类。既然Object是所有类的父类,那么我们就可以通过Object数组来实现异类收集,由于多态性,Object数组就能收集所有种类的元素。
父类的私有方法对于子类来说是不可见的,注意,不可见不等于没有,子类仍旧继承了父类所有的成员,那么这些私有的父类成员去哪了?实际上,它们都被隐藏,对子类来说,这些父类的私有成员都被隐藏了起来,从而导致子类中的不可见。
3.java基本数据类型的封装类
对于每一个 java基本数据类型,java都提供了对应的包装类,如:Boolean、Character、Integer、Double等8
种包装类。在java中,包装类主要是用于将基本数据类型与对象之间进行转换连接。
在5.0中java已实现了自动装、拆箱,即基本类型和对应的包装类之间可以直接赋值,转换的工作由虚拟机代劳了!Integer
numObj =10;语句是正确的!其中基本类型到包装类的自动转换我们称之为自动装箱,反过来就是自动拆箱,比如:
Integer numObj = 10; //自动装箱
int num = numObj; //自动拆箱
因为 java是面向对象语言,我们在许多场合都会将基本类型作为一个对象来处理,因此,包装类就起到了很方便的作用!
包装类有许多共同的方法和静态常量:
valueof(***) --static方法,将对应的基本类型转换成包装类
parseXXX(String) --static方法,将字符串转换成对应的基本类型
toString() --static方法,将基本类型转换成字符串对象
SIZE --静态常量,返回对应基本类型占用的字节位大小
TYPE --静态常量,返回对应的基本数据类型名称
在java中,==与equals()都是用来比较引用,只是==即可以比较基本类型,也可以比
较对象,而 equals()则只能在对象之间进行引用比较。==是对栈中的值进行比较的,如果要比较堆中对象的内容是否相同,那么就要重写equals方法了。 Object类中equals是使用==比较的,所以如果没重写equals方法,和==是一样的效果。Object类中的hashCode是返回对象在内存中地址转换成的一个int值(可以当作地址看)。如果没有重写hashCode方法,任何对象的hashCode都是不相等的。通常集合类需要重写hashCode方法和equals方法,因为如果需要给集合类如HashSet添加对象,那么在添加之前需要查看集合里是否已经有了改对象,比较好的方式就是用hashCode。基本类型封装类也都重写了equals和hashCode方法。
public boolean equals(Object o) {
boolean result = false;
if ((o != null) && (o instanceof Employee)) {
Employee e = (Employee) o;
if (name.equals(e.name)) {
result = true;
}
}
return result;
}
public int hashCode() {
return (name.hashCode());
}
toString 方法被用来将一个对象转换成String表达式。当自动字符串转换发生时,它
被用作编译程序的参照。例如:
Date now = new Date()
System.out.println(now)
将被翻译成:
System.out.println(now.toString());
对象类定义缺省的 toString()方法,它返回完整类名称+@+引用地址(通常情况下不是
很有用)。许多类覆盖 toString()以提供更有用的信息。所有的包装类覆盖toString()以提供它们所代表的值的字符串格式。甚至没有字符串格式的类为了调试目的常常实现toString()来返回对象状态信息。
4 继承与封装的关系
在面向对象系统中,封装性主要指的是对象的封装性,即将属于某一类的一个具体对象封装起来,使其数据和操作成为一个整体。
在引入了继承机制的面向对象系统中,对象依然是封装得很好的实体,其他对象与它进行通讯的途径仍然只有一条,那就是发送消息。
类机制是一种静态机制,不管是基类还是派生类,对于对象来说,它仍然是一个类的实例,既可能是基类的实例,也可能是派生类的实例。
因此,继承机制的引入丝毫没有影响对象的封装性。
继承和封装机制还具有一定的相似性,它们都是一种共享代码的手段。
继承是一种静态共享代码的手段,通过派生类对象的创建,可以接收某一消息,启动其基类所定义的代码段,从而使基类和派生类共享了这一段代码。
封装机制所提供的是一种动态共享代码的手段,通过封装,我们可将一段代码定义在一个类中,在另一个类所定义的操作中,我们可以通过创建该类的实例,并向它发送消息而启动这一段代码,同样也达到共享的目的。
5、 super关键字的用法和位置,super关键字调用父类的构造方法,super关键字调用父类的方法?
在子类的构造方法中,通过super关键字调用父类的构造方法。
如果子类中重写了父类的方法,可以通过super关键字调用父类的方法。
父类:
private String name;
private String sex;
public xinxin1(String name,String sex)
{
this.name=name;
this.sex=sex;
}
public void hello(){
System.out.println(“嗨!我是”+name+”我是”+sex+”孩”);
}
子类:
public xinxin2(String name,String sex)
{
//调用父类的构造方法
super(name,sex);
}
public void hello(){
System.out.println(“我是新来的!”);
//调用父类的方法
super.hello();
}
位置注意:调用父类的构造方法的语句(super语句)必须是构造方法中的第一条语句。
因为创建对象的时候,需要先创建父类对象,再创建子类对象。
注意:创建对象时,先创建父类对象,在创建子类对象。如果没有显示调用父类的构造方法,将自动调用父类的无参构造方法。
6、 一切类的老大(祖先)Object。
所有类都直接或者间接地继承了java.lang.Object类,Object类中定义了所有的java对象都具有的相同行为,是所有类的祖先。
一个类如果没有使用extends关键字,那么这个类直接继承自Object类。
7、 什么是多态?
多态的特征是表现出多种形态,具有多种实现方式。或者多态是具有表现多种形态的能力的特征。或者同一个实现接口,使用不同的实例而执行不同的操作。
8、 为什么需要使用多态?多态的好处?
可以增强程序的可扩展性及可维护性,使代码更加简洁。
不但能减少编码的工作量,也能大大提高程序的可维护性及可扩展性。
9、 如何实现多态?
一般做法是:写一个方法,它只接收父类作为参数,编写的代码只与父类打交道。调用这个方法时,实例化不同的子类对象(new 一个对象)。
更具体的说:
(1)、子类重写父类的方法。使子类具有不同的方法实现。
(2)、把父类类型作为参数类型,该父类及其子类对象作为参数转入。
(3)、运行时,根据实际创建的对象类型动态决定使用那个方法。
在运行时,java虚拟机会根据实际创建的对象类型决定使用那个方法。一般将这称为动态绑定。
10、多态小结:多态与继承、方法重写密切相关,我们在方法中接收父类类型作为参数,在方法实现中调用父类类型的各种方法。当把子类作为参数传递给这个方法时,java虚拟机会根据实际创建的对象类型,调用子类中相应的方法(存在方法重写时)。