黑马程序员 Java面向对象(继承,抽象类,接口,多态,内部类)

时间:2022-06-20 00:48:01

------- android培训java培训、java学习型技术博客、期待与您交流! ----------


面向对象(继承-概述)

       多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。

       多个类可以称为子类,单独这个类称为父类或者超类。

       子类可以直接访问父类中的非私有的属性和行为。

 

       继承的出现提高了代码的复用性。

       继承的出现让类与类之间产生了关系,提供了多态的前提。

      

       注意:千万不要为了获取其他类的功能,简化代码而继承,必须是类与类之间有所属关系才可以继承.

 

       java只支持单继承,不支持多继承,但是java有另外一种体现形式--多实现.

       java支持多层继承,也就是一个继承体系.

 

       如何使用一个继承体系中的功能呢?

       想要使用体系,先查阅体系父类的描述,因为父类中定义的是该体系*性功能。

       通过了解共性功能,就可以知道该体系的基本功能。

       那么这个体系已经可以基本使用了。

       那么在具体调用时,要创建最子类的对象,为什么呢?

       1.因为有可能父类不能创建对象,

       2.创建子类对象可以使用更多的功能,包括基本的也包括特有的。

       简单一句话:查阅父类功能,创建子类对象使用功能。

 

       类与类,事物与事物之间除了继承关系,还有聚合关系和组合关系.

      

面向对象(子父类中变量的特点)

       如果子类中出现非私有的同名成员变量时,

       子类要访问本类中的变量,用this,

       子类要访问父类中的同名变量,用super。

 

       super的使用和this的使用几乎一致。

       this代表的是本类对象的引用。

       super代表的是父类对象的引用。

 

       加载子类class文件的时候先加载父类class文件.

 

面向对象(子父类中函数的特点-覆盖)

       当子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容,如同父类的函数被覆盖一样。

       这种情况是函数的另一个特性:重写(覆盖)。

 

       当子类继承父类,沿袭了父类的功能,到子类中,但是子类虽具备该功能,但是功能的内容却和父类不一致,

       这时,没有必要定义新功能,而是使用覆盖,保留父类的功能定义,并重写功能内容。

 

       覆盖:

       1,子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。

       2,静态只能覆盖静态。

 

       重载:只看同名函数的参数列表。

       重写:子父类方法要一模一样。

 

      

面向对象(子父类中构造函数的特点-子类实例化过程)  

       在对子类对象进行初始化时,父类的构造函数也会运行,

       那是因为子类的构造函数默认第一行有一条隐式的语句 super();

       super():会访问父类中空参数的构造函数。而且子类中所有的构造函数默认第一行都是super();

 

       为什么子类一定要访问父类中的构造函数

       因为父类中的数据子类可以直接获取。所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。

       所以子类在对象初始化时,要先访问一下父类中的构造函数。

       如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。

 

       注意:super语句一定定义在子类构造函数的第一行。

 

       子类的实例化过程。

       结论:

       子类的所有的构造函数,默认都会访问父类中空参数的构造函数。

       因为子类每一个构造函数内的第一行都有一句隐式super();

       当父类中没有空参数的构造函数时,子类必须手动通过super语句形式来指定要访问父类中的构造函数。

       子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数。

       子类中至少会有一个构造函数会访问父类中的构造函数。

 

 

面向对象(final关键字)

       final: 最终。是一个修饰符,

       1,可以修饰类,函数,变量.

       2,被final修饰的类不可以被继承.

       3,被final修饰的方法不可以被复写.

       4,被final修饰的变量是一个常量只能赋值一次,即可以修饰成员变量又可以修饰局部变量.

              当在描述事物时,一些数据的值是固定的,为了增强阅读性,都给这些值起个名字。方便于阅读。

              而这个值不需要改变,所以加上final修饰。常量的书写规范所有字母都大写,

              如果由多个单词组成。单词间通过_连接。

 

面向对象(抽象类)

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

       1,抽象方法一定定义在抽象类中.

       2,抽象方法和抽象类都必须被abstract关键字修饰.

       3,抽象类不可以用new创建对象,因为调用抽象方法没意义,会编译失败.

       4,抽象类中的方法要被使用,必须由子类复写所有的抽象方法,然后建立子类对象调用.

         如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类.

 

       抽象类和一般类没有太大不同,该怎么描述事物还怎么描述,只不过类里面出现了抽象方法.

       抽象类中也可以有非抽象方法,这些方法可以直接被使用.

       注意:抽象类中也可以不定义抽象方法,这样做仅仅是不让该类建立对象.

 

      classEmployee
{
privateString name;
privateString id;
privatedouble pay;

Employee(Stringname,String id,double pay)
{
this.name= name;
this.id= id;
this.pay= pay;
}

publicvoid work();
}

classpro extends Employee
{
Pro(Stringname,String id,double pay)
{
super(name,id,pay);
}

publicvoid work()
{
System.out.println("prowork");
}
}


classManager extends Employee
{
privateint bonus;
Manager(Stringname,String id,double pay,int bonus)
{
super(name,id,pay);
this.bonus= bonus;
}
publicvoid work()
{
System.out.println("managerwork");
}
}

       

面向对象(模版方法模式)

       模版方法设计模式:在定义功能时,功能的一部分是确定的,但是一部分是不确定的.

       而确定的部分在使用不确定的部分,那么这时就将不确定的部分暴露出去,由该类的子类去完成.

abstract class GetTime
{
publicfinal void getTime()
{
longstart = System.currentTimeMillis();

runcode();

longend = System.currentTimeMillis();

System.out.println("毫秒:"+(end-start));
}
publicabstract void runcode();
}

class SubTime extends GetTime
{

publicvoid runcode()
{
for(intx=0; x<4000; x++)
{
System.out.print(x);
}
}
}

class TemplateDemo
{
publicstatic void main(String[] args)
{
//GetTimegt = new GetTime();
SubTimegt = new SubTime();
gt.getTime();
}
}

 

面向对象(接口)

       接口:初期可以理解为是一个特殊的抽象类.当类中的方法都是抽象的就可以通过接口的形式来表示.

       interface:用于定义接口. class:用于定义类.

      

       接口定义时,格式特点:

       1,接口中常见定义:常量,抽象方法.

       2,接口中的成员都有固定修饰符.

       常量:public static final  方法:public abstract

 

       接口中的成员都是public的.

       接口是不可以创建对象的,因为有抽象方法.

       需要被子类实现,子类对接口的抽象方法全都覆盖后,子类才可以实例化,否则子类是一个抽象类.

 

       接口可以被类多实现,java不支持类与类的多继承但是支持类与接口的多实现.

       接口与接口之间可以继承,而且支持多继承.

 

面向对象(接口的特点)

       1,接口是对外暴露的规则.

       2,接口是程序的功能扩展.

       3,接口的出现降低耦合性。

       4,接口可以用来多实现。

       类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。

       接口与接口之间可以有继承关系。

       例如:电脑主板和不同厂家的元件可以通过统一的插槽进行连接,符合规则就可以用.

 

       抽象类和接口异同:

       相同:

       1,都可以在内部定义抽象方法。

       2,通常都在顶层。

       3,都不可以实例化,都需要子类来实现。

       不同点:

       1,抽象类中可以定义抽象方法和非抽象方法,而接口中只能定义抽象方法。

       2,接口的出现可以多实现。抽象类只能单继承。也就是说:接口的出现避免了单继承的局限性。

       3,继承和实现的关系不一致。继承:is a,实现:like a

 

 

 

面向对象(多态-概念)

       多态:某一类事物的多种存在形态。

       例如:动物中有猫和狗。

       猫这个对象对应的类型是猫类型

              猫 x = new 猫();

       同时猫也是动物中的一种,也可以把猫称为动物。

              动物 y = new 猫();

       动物是猫和狗具体事物中抽取出来的父类型。

       父类型引用指向了子类对象。

 

       1,多态的体现

              父类的引用指向了自己的子类对象。

              父类的引用也可以接收自己的子类对象。

       2,多态的前提

              必须是类与类之间有关系。要么继承,要么实现。

              通常还有一个前提:存在覆盖。

       3,多态的好处

              多态的出现大大的提高程序的扩展性。

       4,多态的弊端:

              提高了扩展性,但是只能使用父类的引用访问父类中的成员。

 

面向对象(多态-转型)

       instanceof: 用于判断对象的类型。 对象 intanceof 类型(类类型接口类型) 

 

       Animala = new Cat();//类型提升。 向上转型。

       a.eat();

 

       如果想要调用猫的特有方法时,如何操作?

       Catc = (Cat)a;//强制将父类的引用。转成子类类型。向下转型。

       c.catchMouse();

 

       多态自始至终都是子类对象在做着变化

       千万不要出现这样的操作,就是将父类对象转成子类类型。

 

面向对象(多态中成员的特点)

       在多态中成员函数的特点:

       在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。

       在运行时期:参阅对象所属的类中是否有调用的方法。

       简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。

 

       在多态中成员变量的特点:

       无论编译和运行,都参考左边(引用型变量所属的类)。

 

       在多态中,静态成员函数的特点:

       无论编译和运行,都参考做左边。

 

 

面向对象(多态的主板示例)

interface PCI
{
publicvoid open();
publicvoid close();
}

class MainBoard
{
publicvoid run()
{
System.out.println("mainboardrun ");
}
publicvoid usePCI(PCI p)//PCI p = new NetCard();接口型引用指向自己的子类对象。
{
if(p!=null)
{
p.open();
p.close();
}
}
}

class NetCard implements PCI
{
publicvoid open()
{
System.out.println("netcardopen");
}
publicvoid close()
{
System.out.println("netcardclose");
method();
}

}
class SoundCard implements PCI
{
publicvoid open()
{
System.out.println("SoundCardopen");
}
publicvoid close()
{
System.out.println("SoundCardclose");
}
}

class DuoTaiDemo5
{
publicstatic void main(String[] args)
{
MainBoardmb = new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(newNetCard());
mb.usePCI(newSoundCard());
}
}

 

面向对象(多态的扩展示例)

/*
需求:数据库的操作。
数据是:用户信息。
1,连接数据库。JDBC Hibernate
2,操作数据库。c create r read u update d delete
3,关闭数据库连接。
*/

interface UserInfoDao
{
publicvoid add(User user);
publicvoid delete(User user);
}

class UserInfoByJDBC implements UserInofDao
{
publicvoid add(User user)
{
1,JDBC连接数据库。;
2,使用sql添加语句添加数据。;
3,关闭连接。
}
publicvoid delete(User user)
{
1,JDBC连接数据库。;
2,使用sql添加语句删除数据。;
3,关闭连接。
}
}

class UserInfoByHibernate implementsUserInfoDao
{
publicvoid add(User user)
{
1,Hibernate连接数据库。;
2,使用sql添加语句添加数据。;
3,关闭连接。
}
publicvoid delete(User user)
{
1,Hibernate连接数据库。;
2,使用sql添加语句删除数据。;
3,关闭连接。
}
}

class DBOperate
{
publicstatic void main(String[] args)
{
//UserInfoByJDBCui = new UserInfoByJDBC();
//UserInfoByHibernateui = new UserInfoByHibernate();
UserInfoDaoui = new UserInfoByHibernate();
ui.add(user);
ui.delete(user);
}
}


 

面向对象(Object类)

       Object:是所有对象的直接后者间接父类,传说中的上帝。

       它里面的方法是所有对象都具备的。

 

       常见方法:

       booleanequals(Object obj):用于比较两个对象是否相同。

       StringtoString(): 获取对象的字符串表现形式 类名@哈希值。

       ClassgetClass():获取正在运行的对象所属的字节码文件的对象。

 

       Object类中已经提供了对象是否相同的比较方法。

       如果自定义类中也有比较相同的功能,没有必要重新定义。

       只要沿袭父类中的功能,建立自己特有比较内容即可。这就是覆盖。

 

class Demo
{
privateint num;
Demo(intnum)
{
this.num= num;
}
//复写equals方法
publicboolean equals(Object obj)
{
if(!(objinstanceof Demo))
returnfalse;
Demod = (Demo)obj;
returnthis.num == d.num;
}
/*
publicboolean compare(Demo d)
{
returnthis.num==d.num;
}
*/
//复写toString方法
publicString toString()
{
return"demo:"+num;
}
}


面向对象(内部类)

       内部类的访问规则:

       1,内部类可以直接访问外部类中的成员,包括私有。

       之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式 外部类名.this

       2,外部类要访问内部类,必须建立内部类对象。

             

       访问格式:

       1,当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,直接建立内部类对象。

              外部类名.内部类名  变量名 = 外部类对象.内部类对象;

              Outer.Innerin = new Outer().new Inner();

 

       2,当内部类在成员位置上,就可以被成员修饰符所修饰。

              比如,private:将内部类在外部类中进行封装。

              static:内部类就具备static的特性。

              当内部类被static修饰后,只能直接访问外部类中的static成员。出现了访问局限。

 

              在外部其他类中,如何直接访问static内部类的非静态成员呢?

              newOuter.Inner().function();

 

              在外部其他类中,如何直接访问static内部类的静态成员呢?

              Outer.Inner.function();

 

       注意:当内部类中定义了静态成员,该内部类必须是static的。

                当外部类中的静态方法访问内部类时,内部类也必须是static的。

 

       内部类定义在局部时,

              不可以被成员修饰符修饰

              可以直接访问外部类中的成员,因为还持有外部类中的引用。

           但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。

 

       匿名内部类:

       1,匿名内部类其实就是内部类的简写格式。

       2,定义匿名内部类的前提:内部类必须是继承一个类或者实现接口。

       3,匿名内部类的格式:new 父类或者接口(){定义子类的内容}

       4,其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。  可以理解为带内容的对象。

       5,匿名内部类中定义的方法最好不要超过3个。

 

/*分析事物时,发现该事物描述中还有事物,而且这个事物还在访问被描述事物的内容。
这时就是还有的事物定义成内部类来描述。*/
class Outer
{
privatestatic int num = 31;

classInner// 内部类。
{
voidshow()
{
System.out.println("showrun..."+num);
}
/*staticvoid function()//如果内部类中定义了静态成员,该内部类也必须是静态的。
{
System.out.println("functionrun ...."+num);
}
*/
}

publicvoid method()
{
Innerin = new Inner();
in.show();
}
}

class InnerClassDemo
{
publicstatic void main(String[] args)
{
Outerout = new Outer();
out.method();
//直接访问外部类中的内部类中的成员。
Outer.Innerin = new Outer().new Inner();
in.show();

//如果内部类是静态的。 相当于一个外部类
Outer.Innerin = new Outer.Inner();
in.show();

//如果内部类是静态的,成员是静态的。
Outer.Inner.function();
}
}





------- android培训java培训、java学习型技术博客、期待与您交流! ----------