黑马程序员--JAVA<面向对象>--构造函数、抽象类、接口、多态

时间:2023-02-18 08:11:06

---------------------- ASP.Net+Android+IO开发S.Net培训、期待与您交流! ----------------------

理解面向对象

·何为面向对象?

面向对象是相对于面向过程而言的,面向过程强调的是功能的行为,强调的是一种动作,面向对象强调的是具备该功能的对象。java中,把各功能封装到对象中,在建立对象的时候,该对象就具备了这些功能,功能的行为是通过对象的调用来实现的,所以java是面向对象的。

·类与对象的关系

可以把类理解为是对象的设计图,对象就是根据类设计出来的产品。类中封装了各功能,我们通过建立该类的对象对这些功能进行调用,一个类可以建立多个对象并被其调用其功能。

·封装

在程序设计的时候,我们有时候不想把其中的成员对外暴露,但是其功能或值需要提供给别人使用,这时候,可以用private把该成员私有化,并提供一个功能给别人操作该成员,这样就是封装。

·对象的建立与功能调用

格式:对象建立:类名 对象名 = new 类名();       功能调用:对象名.功能名();

构造函数

·何为构造函数?

1.函数名与类名相同
2.不用定义返回值类型。
3.不用写return语句。
class Test
{
Test()//这个就是构造函数。
{
}
}

·构造函数的特点与作用

1.对象建立的时候就会调用与之对应的构造函数。
2.当一个类中没有定义构造函数时,系统会默认给该类加入一个空参数的构造函数 : 类名(){}。 3.当在类中自定义了构造函数的时候,类中默认的构造函数就没有了。 4.对象建立的时候,可以把参数传入对象中的构造函数给对象初始化,但是要能找到对应的构造函数,如果没有找到,则编译失败。 5.一般函数和构造函数在写法上不同,在运行上也有不同。
构造函数是在对象建立就运行,给对象初始化
  一般函数是是对象调用的时候才执行,是给对象添加对象具备的功能。
  对象建立时构造函数只运行一次,一般函数可以被对象调用多次。
5.构造函数的作用:用于给对象进行初始化。 当分析事物时,该事物具备一些特性或行为,就需要将这些内容定义在构造函数中。

·构造代码块

作用:给对象进行初始化。
对象一建立就运行,而且优先于构造函数执行。
 

·构造代码块与构造函数的区别

1.构造代码块是给所有对象进行初始化。
2.构造函数是给对应的对象进行初始化。
3.构造代码块定义的是不同对象共性的初始化内容。
class Test
{
//构造代码块,没有函数名,只有 {语句}
{
System.out.println("初始化");
}
Test()//系统默认会加入此构造函数。
{}
Test(int a)//定义了其他构造函数以后,系统就不会加入Test()函数。
{}
run()
{}
}
class Demo
{
public static void main(String[] args)
{
//在建立对象的时候,构造函数就会运行,给对象初始化,并且只运行一次。构造代码块也会运行,并且优先于其他构造函数运行。
Test t = new Test();//建立一个对象以后,会直接调用Test()构造函数,给该对象初始化。
Test t1 = new Test(1);//建立一个对象,并且把1的值传给Test(int a)构造函数,给该对象初始化。
Test t2 = new Test(3,4);//错误,因为Test类中没有Test(int a, int b)构造函数。
//对象建立以后,可以多次调用其中的一般函数。
t.run();
t.run();
}
}

抽象类

·抽象类定义

当多个类中出现相同功能,但是功能的主体不同,这时可以进行向上抽取,只抽取功能定义,不抽取功能主体。

·抽象类的特点

1.抽象方法一定定义在抽象类中。
2.抽象方法和抽象类都必须被abstract关键字修饰。abstract只能修饰类或者方法,不能定义变量等。
3.抽象类不可以用new建立对象,因为调用抽象方法没有意义。
4.抽象类中的方法要被使用,必须由子类复写其所有的抽象方法后,才可以建立子类对象调用。
    如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。
5.抽象类不可以被实例化。
    Test t = new Test();是不可行的。
6.特殊:
    抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象
abstract class Test //这是个抽象类,必须用abstract修饰
{
abstract void run1(); //这个是抽象方法。必须用abstract修饰
abstract void run2(); //这个是抽象方法。必须用abstract修饰
abstract void run3(); //这个是抽象方法。必须用abstract修饰
void run4(){} //这个不是抽象方法。
}


class Demo extends Test //这个是Test的子类
{
void run1(){} //Test中run1()是抽象方法,所以必须复写。
void run2(){} //Test中run2()是抽象方法,所以必须复写。
void run3(){} //Test中run3()是抽象方法,所以必须复写。
//void run4(){} //Test中run4()不是抽象方法,所以可以不复写。
}

·抽象类和一般类的区别

1.抽象类和一般类没有太大的不同。该如何描述事物就如何描述事物,只是该事物出现了一些看不懂的东西。这些不确定的部分,也是该事物的功能,需要明确出来,但是无法    定义主体,就通过抽象方法来表示。
2.抽象类比一般类多了抽象函数。就是在类中可以定义抽象方法。

·模板方法设计模式

在定义功能时,功能的一部分是确定的,有一部分是不确定的,而确定的部分在使用不确定的部分。
那么这时,就将不确定的部分暴露出去,由该类的子类去完成。
abstract class GetTime
{
//确定部分。
public final void getTime() //final的作用是不想getTime方法被子类复写。
{
long start = System.curentTimeMillis();//获取时间.
runcode(); //调用不确定部分的函数,此函数必须被子类复写。
long end = System.curentTimeMillis();
System.out.println("毫秒:"+(end - start));
}
//不确定部分。
public abstract void runcode(); //抽象函数,必须被子类复写以后才能使用。
}


class SubTime extends GetTime
{
//复写父类的抽象函数。
public void runcode()
{
for(int x=0;x<4000;x++)
{
System.out.print(x);
}
}
}

接口

·何为接口

初期理解,可以认为是一个特殊的抽象类。 当抽象类中的方法是抽象的,该类就可以通过接口的形式来表示。 
    class用于定义类 
    interface用于定义接口。 接口里面的函数都是抽象函数。 

·接口与类的区别

1.接口在定义时,格式特点 
1.1.接口中常见定义:常量、抽象方法。 
1. 2.接口中的成员都有固定修饰(不管写不写,系统都默认加上此修饰符,但是为了阅读方便,要写全。) 
        常量:public static final 
        方法:public abstract 
        接口中的成员都是public的。
interface PCI
{
public static final int x = 3; //由于变量是final的,所以接口中定义的都是常量。
public static abstract run(); //接口中的函数都是抽象的。
}
2.类与类之间是继承关系。接口是实现关系。
    class Test extends Test1   继承
    class Test implements Test1   接口实现。

3.接口是不可以创建对象的,因为有抽象方法。需要被子类实现,子类对借口中的抽象方法全部覆盖后,子类才可以实例化。否则子类就是一个抽象类。实现了接口的子类之中的方法必须也是public的,因为接口中的函数都是public的。接口可以被类多实现。(类不可以多继承)这是对多继承不支持的转换形式,java能多实现。
4.一个类可以在继承一个类的同时实现多个接口。
class Test extends Demo implements Demo1,Demo2. //可以在继承了一个类Demo的同时实现Demo1、Demo2...多个接口。
{
}
5.类与类之间是继承关系,类与接口之间是实现关系,接口与接口间是继承关系。接口之间可以实现多继承。

·接口的特点

1.接口是对外暴露的规则。
2.接口是程序的功能扩展
3.接口可以用来多实现。
4.类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口
5.接口与接口之间可以有继承关系。

·简单小程序

/*
需求:电脑运行实例
电脑运行基于主板


设计思想:
电脑基于主板运行,主板提供PCI插槽便于后期扩展。
后期产品(声卡、显卡等)符合PCI规则加载到主板运行。


设计思想:主板提供PCI接口,显卡、声卡等后期的硬件通过实现PCI接口规则,加载至主板运行。
*/




interface PCI //定义一个接口。便于后期扩展。
{
public abstract void open();
public abstract void closs();
}


class Zhuban //主板,设计初期没有任何其他硬件,但是提供PCI接口引用。
{
void run() //自身函数。
{
System.out.println("zhuban run");
}
void usePCI(PCI p) //使用PCI接口上的硬件。
{
if (p!=null) //判断PCI接口是否有硬件。
{
p.open();
p.closs();
}
}
}
//-------------------------------------------------------------------
class PCrun //相当于电脑。
{
public static void main(String[] args)
{
Zhuban zb = new Zhuban(); //建立主板对象。
zb.run(); //调用主板中自身的函数。
zb.usePCI(null); //未加载PCI硬件。
zb.usePCI(new Xianka()); //使用PCI上的xianka()硬件
}
}
//-------------------------------------------------------------------
class Xianka implements PCI //相当于显卡。实现PCI接口。这个是后期定义的类(相当于后期加入的硬件)
{
public void open() //复写PCI中的open()抽象函数
{
System.out.println("xianka open");
}
public void closs() //复写PCI中的吃closs()抽象函数
{
System.out.println("xianka closs");
}
}

多态

·何为多态

某一事物存在的多种体现形态。
例:
人:男人、女人。
动物:猫、狗
猫 X = new 猫();
动物 X = new 猫();类型提升,向上转型。

·多态的特点

1.多态的体现
父类的引用指向了自己的子类对象。
Animal a = new Cat();
父类的引用也可以接收自己的子类对象。
function(new Cat());//接受子类对象: new Cat();
2.多态的前提
必须是类与类之间有关系,要么继承,要么实现。
class Cat extends Animal //Cat类继承Animal
通常还有一个前提,存在覆盖。
Cat类中eat(){}覆盖Animal中的抽象函数eat();
 3.多态的好处
多态的出现大大的提高了程序的扩展性。
后期扩展
class Dog extends Animal
{
}
调用
function(new Dog());
4.多态的弊端
提高了扩展性,但是只能使用父类的引用访问父类中的成员。
附:
abstract class Animal
{
abstract void eat();
}
class Cat extends Animal
(
void eat()
{
System.out.println("吃鱼");
}
void cachMouse()
{
System.out.println("抓老鼠");
}
)
//--------------------------------------------------
class Demo
{
public static void main(String[] args)
{
Animal a = new Cat();
a.cachMouse();//不可行,因为Animal类(父类)中没有cachMouse()方法。
function(new Cat());
function(new Dog());
}
public static void function(Animal a)
{
a.eat();
}
}
//--------------------------------------------------
class Dog extends Animal //后期拓展。
{
void eat()
{
System.out.println("啃骨头");
}
void kanJia()
{
System.out.println("看家");
}
}
5.多态的出现代码中的特点(多态使用的时候注意事项)在多态中成员函数的特点:
在编译时期,参与引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。
在运行时期,参与对象所属的类中是否有调用的方法。
总结:成员函数在多态调用时,编译看左边,运行看右边。

在多态中,成员变量的特点。
无论编译和运行,都参考左边(引用型变量所属的类)。

在多态中,静态成员函数的特点:
无论编译和运行,都参考左边。(静态不存在覆盖)
abstract class Fu
{
int num = 5;
void run1(){}
void run2(){}
static run4(){}
}
class Zi extends Fu
{
int num = 8;
void run1(){};
void run3(){};
static run4(){}
}
class Test
{
public static void main(String[] args)
{
Fu f = new Zi();
f.run1();//编译成功,因为Fu f = new Zi(); 左边是Fu类型的,有run1()函数。
输出结果是Zi类中run1()的结果,因为Fu f = new Zi(); 右边是Zi类型的存在覆盖。
f.run2();//编译成功,因为Fu f = new Zi(); 左边是Fu类型的,有run2()函数。输出结果是Fu类中run2()的结果,因为不存在覆盖。
f.run3();//编译失败,因为Fu f = new Zi(); 左边是Fu类型的,没有run3()函数。
Fu f1 = new Zi();
f1.num == 5;//参考左边
Zi z = new Zi();
z.num == 8;//参考左边
Fu f2 = new Zi();
f2.run4();//输出结果为Fu类中run4()中的结果,因为Fu f2 = new Zi(); 左边是Fu类型(静态不存在覆盖)
Zi z1 = new Zi();
z1.run4();//输出结果为Zi类中run4()中的结果,因为Zi z1 = new Zi();;左边是Zi类型
}
}
6.不能将父类对象转成子类类型。父类引用指向了自己的子类对象时,该引用可以被提升,也可以被强制转换。多态自始至终都是子类对象在做变化。
    Animal a = new Cat();类型提升,向上转型
    强制将父类的引用转成子类类型,向下转型。
    Cat c = (Cat)a;
    c.cachMouse();可用。
---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------详细请查看:http://edu.csdn.net