一、类的继承
继承在面向对象开发思想中是一个非常重要的概念,它使整个程序架构具有一定的弹性,在程序中复用一些已经定义完善的类不仅可以减少软件开发周期,同时也可以提高软件的可维护性和可扩展性。
Java中运用extends关键字来标识两个类的继承关系。
package bao;
class Demo1{
public Demo1() { //构造方法
}
protected void domoni() { //成员方法
}
protected Demo1 doot() { //方法返回值类型为Demo1类型
return new Demo1();
}
}
class Demo2 extends Demo1{ //继承父类
public Demo2() { //构造方法
super(); //super调用父类构造方法
super.domoni(); //super调用父类成员方法
}
public void domoi11() { //新增方法
}
public void domoni() { //重写父类方法
}
protected Demo2 doot() { //重写父类方法,方法 返回值类型为Demo2类型
return new Demo2();
}
}
继承代码分析:
package bao;
class Demo1{
public Demo1() { //构造方法
System.out.println("我是父类Demo1");
}
}
class Demo2 extends Demo1{ //继承父类Demo1
public Demo2() { //构造方法
System.out.println("我是子类Demo2");
}
}
class Demo3 extends Demo2{
Demo3(){
System.out.println("我是子类Demo3");
}
public static void main(String[] args) {
Demo3 d=new Demo3(); //实例化子类对象
}
}
/*输出结果:
我是父类Demo1
我是子类Demo2
我是子类Demo3
*/
二、Object类
Object类是比较特殊的类,它是所有类的父类,是Java类层中的最高层类,实质上Java中任何一个类都是它的子类。
1、getClass()方法
(1)getClass()方法是获得调用该方法的对象的类;getClass().getName()可以得到该类的路径。
getClass().getname();
(2)通过getClass()方法得到该对象类Class后,可以通过Class获取这个类中的相关属性和方法。
2、toString()方法
toString()方法的功能会将一个对象改变为字符串。
package bao;
public class Demo1{
public String toString() { //重写成toString()方法
return "在"+getClass().getName()+"类中重写toString()方法";
}
public static void main(String[] args) {
System.out.println(new Demo1());
}
}
/*输出结果:
在bao.Demo1类中重写toString()方法
*/
3、equals()方法
在Java语言中有两种对象的比较方式,分别为“==”运算符与equals()方法。
package bao;
import java.util.Arrays;
public class Demo1 {
public static void main(String[] args) {
String str=new String("aaa");
String str1=new String("aaa");
String str2=str;
//运用“==”运算符比较str1与str2
System.out.println("“==”运算符比较str1与str2的结果:"+(str1==str2));
//运用“equals()”方法比较str1与str2
System.out.println("“equals()”方法比较str1与str2的结果:"+str1.equals(str2));
}
}
/*输出结果:
“==”运算符比较str1与str2的结果:false
“equals()”方法比较str1与str2的结果:true
*/
“==”:是比较两个对象的地址是否相同
equals():是比较两个对象的内容是否相同
三、对象类型的转换
1、向上转型
例如,一只鸭是家禽的一种,而家禽是动物中的一种,那么也可以将鸭对象看作是一个动物对象。
fulei dx=new zilei();
fulei :父类
zilei:子类
Demo1是代表家禽类,Demo2是代表鸭子类。运用Demo2鸭子类继承Demo1家禽类,然后调用主方法draw()调用父类方法。
package bao;
public class Demo1{ //家禽类
public static void draw(Demo1 jia) { //家禽类的方法
}
public static class Demo2 extends Demo1{
public static void main(String args[]) {
Demo2 ya=new Demo2(); //实例化鸭子类的对象引用
draw(ya);
}
}
}
2、向下转型
通过向上转型可以推理出向下转型是将较抽象类转换为较具体的类。这样的转型通常会出现问题,例如,不能说四边形是平行四边形的一种,不能说所有的鸟都是鸽子,这非常不合乎逻辑。可以说子类对象总是父类的一个实例,但父类对象不一定是子类的实例。
fulei a=new zilei();
zilei b=(zilei)a;
fulei :父类
zilei:子类
package bao;
public class Demo1{ //家禽类
public static void draw(Demo1 jia) { //家禽类的方法
}
public static class Demo2 extends Demo1{
public static void main(String args[]) {
draw(new Demo1()); //将鸭子看成是家禽
Demo1 jia=new Demo2();
//Demo2 ya=jia; 将家禽类对象赋予鸭子类对象,是错误的
Demo2 ya=(Demo2)jia; //将家禽类对象赋予鸭子类对象并强制转换成子类型,是正确的
}
}
}
四、instanceof判断对象类型
当在程序中执行向下转型操作时,如果父类对象不是子类对象的实例,就会发生ClassCastException异常,所以在执行向下转型之前需要养成一个良好的习惯,就是判断父类对象是否为子类对象的实例。这个判断通常使用instanceof操作符来完成。
zilei instanceof fulei
zilei:子类对象
fulei:父类对象
package bao;
public class Demo1{
public static void draw(Demo1 q) {
}
}
class Demo2 extends Demo1{
}
class Demo3{
}
class Demo4 extends Demo1{
public static void main(String args[]) {
Demo1 a=new Demo1(); //父类实例化
if(a instanceof Demo4) { //判断父类对象是否为Demo4子类的一个实例化
Demo4 d=(Demo4)a;
}
if(a instanceof Demo2) { //判断父类对象是否为Demo2子类的一个实例化
Demo2 s=(Demo2)a;
}
}
}
五、方法重载
方法的重载就是在同一个类中允许同时存在一个以上的同名方法,只要这些方法的参数个数或类型不同即可。
package bao;
public class Demo1{
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(double b,int a)
* public static int add(int a,double b)
* 以上两行参数对比参数顺序不同,构成重载
*
* */
public static int add(int a,double b) { //参数顺序不同,构成重载。
return 1;
}
public static void main(String args[]) {
System.out.println("调用 add(int a,int b)方法:"+add(1,2));
System.out.println("调用 add(double a,double b)"+add(2.1,3.6));
System.out.println("调用 add(int a)"+add(1));
}
}
/*输出结果:
调用 add(int a,int b)方法:3
调用 add(double a,double b)5.7
调用 add(int a)1
*/
1、参数类型不同,构成重载。
2、参数顺序不同,构成重载。
3、参数个数不同,构成重载。
六、多态
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
多态性是面向对象程序设计的重要部分。在Java中,通常使用方法的重载(Overloading)和重写(Overriding)实现类的多态性。
package bao;
public class Demo1{
private Demo1[] qt=new Demo1[6];
private int index=0;
public void draw(Demo1 a) {
if(index<qt.length) {
qt[index]=a;
System.out.println(index);
index++;
}
}
public static void main(String args[]) {
Demo1 a=new Demo1();
a.draw(new Demo2()); //调用黑白打印
a.draw(new Demo3()); //调用彩色打印
}
}
//定义黑白打印的类Demo2
class Demo2 extends Demo1{
public Demo2() {
System.out.println("黑白打印");
}
}
//定义彩色打印的类Demo3
class Demo3 extends Demo1{
public Demo3() {
System.out.println("彩色打印");
}
}
/*输出结果:
黑白打印
0
彩色打印
1
*/
七、抽象类与接口
1、抽象类
在解决实际问题时,一般将父类定义为抽象类,需要使用这个父类进行继承与多态处理。如鸽子类继承鸟类、鸟类继承动物类等。
抽象类的关键字是abstract。
public abstract Yesst{
abstract void testAbstract(); //定义抽象方法
}
2、接口
(1)接口
接口是抽象类的延伸,可以将它看作是纯粹的抽象类,接口中的所有方法都没有方法体。
定义接口关键字是interface。
实现接口关键字是implements。
package bao;
interface jiekou{ //定义接口
public void draw(); //定义方法
}
//定义平行四边形,该类继承了四边形类,并实现了jiekou接口
class Demo2 extends Demo1 implements jiekou{
public void draw() { //由于该类实现了接口,所以需要draw()方法
System.out.println("平行四边形.draw()");
}
void doany() { //覆盖父类
}
}
class Demo3 extends Demo1 implements jiekou{
public void draw() {
System.out.println("正方形.draw()");
}
void doany() {
}
}
class Demo4 extends Demo1{ //定义四边形类
void doany() {
}
}
public class Demo1{ //定义四边形类
public void doAny() {
}
public static void main(String[] args) {
jiekou[]d= { //接口也可以向上转型操作
new Demo2(),new Demo3()};
for(int i=0;i<d.length;i++) {
d[i].draw(); //调用 draw()方法
}
}
}
/*输出结果:
平行四边形.draw()
正方形.draw()
*/
(2)接口与继承
class 类名 implements 接口1,接口2......,接口n
interface intf1{
}
interface intf2 extends intf1{
}
八、附加
public static void main(String[] args) 与public static void main(String args[]) 的区别:
String args[]:单从类型上来讲属于字符串类型, 而从变量本身来讲是一个数组类型, 因此组合起来说明此变量为一个字符串类型的数组, 也就是说数组中的所有元素都为String类型。
String[] args:单从类型上来讲属于字符串数组类型, 而从变量本身来讲就是一个单纯的引用变量, 因此这种方式可以更明显地体现出是否为数组这一点. 因为从类型上就可以直接看出变量为一数组类型引用。