黑马程序员——005——面向对象②(封装、继承、多态)
来源:互联网 发布:windows xp 游戏 编辑:程序博客网 时间:2024/04/30 10:27
首先对上一节课中的单例模式进行复习,并且在这里我做了一些优化,简化了代码:
————————————————————————————
class Demo5_1{ public static void main(String[] args) { Single s1 = Single1.getInstance(); Single s2 = Single1.getInstance(); System.out.println(s1==s2);//打印true s1 = Single2_1.getInstance(); s2 = Single2_1.getInstance(); System.out.println(s1==s2);//打印true s1 = Single2_2.getInstance(); s2 = Single2_2.getInstance(); System.out.println(s1==s2);//打印true }}class Single{}class Single1 extends Single{ //饿汉式,一上来就生成实例 static private Single1 s = new Single1(); private Single1(){} public static Single1 getInstance() { return s; }}class Single2_1 extends Single{ //懒汉式1,需要的时候才生成实例 static private Single2_1 s = null; private Single2_1(){} public static Single2_1 getInstance() { if(s==null) s = new Single2_1(); return s; }}/*上面这一种懒汉式面对多线程的时候并不能够保证单例因此有了下面的优化,*/class Single2_2 extends Single{ //懒汉式2,需要的时候才生成实例 static private Single2_2 s = null; private Single2_2(){} public static Single2_2 getInstance() { if(s==null) { //synchronized代码块只允许一个线程访问, //因此保证了单线程 synchronized(Single2_2.class) { if(s==null) s = new Single2_2(); } } return s; }}
————————————————————————————
仔细观察可以发现,这节课我们只使用了两个引用变量,上一小节中使用了六个变量。
这个便捷的使用方式就是面向中的多态的体现。
我们注意到其中多了一个类那就是Single,然后其他的三个类Single1、Single2_1和Single2_2在class声明的时候都用一个关键字“extends”来连接Single;
这个就是面向对象中的继承,类的继承,extends在这里可以理解为继承。
————————————————————————————
事物之间若存在一些共性,我们是可以将其抽取出来的,比如说学生和工人,本来是两个单独的类,但是他们共性的地方就是他们都是人,都有姓名性别年龄这些成员属性;代码呈现如下:
————————————————————————————
class Student{ private String name; private String sex; private int age; private void learn()//学生特有方法学习 {}}class Worker{ private String name; private String sex; private int age; private void work()//工人特有方法工作 {}}
————————————————————————————
我们发现姓名性别年龄这些成员属性都是重复的,那么何不抽取出来成为一个类,然后让其他两个类共享就可以了!学生和工人都是人类,都有姓名性别年龄这些成员属性,于是就变成下面这样:
————————————————————————————
class Person{ public String name; public String sex; public int age;}class Student extends Person{ private void learn()//学生特有方法学习 {}}class Worker extends Person{ private void work()//工人特有方法工作 {}}class Demo5_2{ public static void main(String[] args) { Person s = new Student(); s.name = "张三"; System.out.println(s.name); Person w = new Worker(); w.name = "李四"; System.out.println(w.name); }}
————————————————————————————
Java中这种使用extends 连接一个类的方式就是继承,extends后面的就成为前面类的父类,写在前面的类就叫做子类;我们可以看到上面的示例,继承之后,子类可以得到父类中public的成员变量,而不需要在自己的类中声明;
所以说继承
—提高了代码的复用性;
—让类与类之间产生了关系,有了这个关系,才有了多态(下面介绍)的特性。
注意:
—千万不要为了获取其他类的功能而采用继承的方式,使用继承必须是类与类之间有所属于关系才可以继承。也就是正确的关系应该是A is a B,才能class A extends B,比如Student is a Person。
—我们不能够让Woker继承Student,而是要让Worker和Student都继承Person;
————————————————————————————
Java语言中(C++是富二代,因为支持多继承),只支持单继承,也就是类后面只能extends一个类;
—多继承容易引起安全隐患,如下例中,当两个父类中出现同名方法的时候:
—红色箭头处,我们是不能够确定的知道是要执行A类的show方法还是B类的show方法。
————————————————————————————
而Java正是对C++多继承的形式改良了
—以多实现的方式来代替了:
————————————————————————————
Java支持多层继承,也就是一层一层继承下去的一个继承体系,比如API文档中的FileInputStream类,如下图:
又如儿子继承父亲,父亲继承爷爷等。用代码体现就是:
——————————————————————
class A{}
class B extendsA{}
class C extendsB{}
——————————————————————
那么要了解一个体系中,先查体系中父类的描述,因为父类中定义的是该体系中的共性功能。通过了解共性功能,就可以知道该体系的基本功能。这样这个体系就可以基本使用了。
—在具体调用时,要创建最子类的对象。原因:
——①是因为有可能父类不能创建对象。
——②是创建子类对象可以使用更多的功能,包括基本的也包括特有的。
简单一句就是:查阅父类功能,创建子类对象使用功能。
————————————————————————————
子父类出现后,类成员的特点:
—类成员:变量,函数,构造函数。
—①变量
——如果子类中出现非私有的同名成员变量时,子类要访问本类中的变量,用this。子类要访问父类中的同名变量,用super。
——super的使用和this的使用几乎一致,且两者都存在于方法区中。
——this表示本来对象的引用。
——super表示父类对象的引用。
—②函数——覆盖
——当子类出现和父类一模一样的函数时,当子类对象调用该函数,会运行子类函数的内容。如同父类的函数被覆盖一样。这种情况是函数的另一个特性:重写(覆盖)。
——当子类继承父类,沿袭了父类的功能,到子类中。但是子类虽具备该功能,但是功能的内容却和父类不一致,这时,没有必要定义新功能,而是使用覆盖特性,保留父类的功能定义,并重写功能内容。子类同时具有父类方法中的内容时,可以用super.方法();
——下面覆盖示例代码一则:
————————————————————————————
class Demo5_3{ public static void main(String[] args) { Person s = new Student(); s.walk();//打印 跳着走路 //由于子类已经覆盖了walk方法 //而且上面new的是Student的对象 }}class Person{ public String name; public String sex; public int age; public void walk() { System.out.println("普通走路!"); }}class Student extends Person{ public void walk()//覆盖父类walk的方法 { System.out.println("跳着走路!"); } private void learn()//学生特有方法学习 {}}
————————————————————————————
关于子父类还有几点要注意的地方:
—①子类覆盖父类,必须保证子类权限大于等于父类权限,才可以覆盖,否则编译失败。
——父类方法是不写(也就是默认权限),子类不能死private,因为默认权限介于private和public之间!
—②静态只能覆盖静态。
——因为没有对象的只有类的时候,内存中只要静态而没有非静态,因此非静态是不能覆盖静态的。
—③父类中的私有方法是不能被重写的。
重载和重写(覆盖)的区别:
—父类有private方法的时候,子类继承父类,并没有继承这个方法,因为是私有的,子类都不知道这个方法,如果子类也写了个同名方法,那不叫覆盖。
只有子类知道父类的方法,也就是父类方法暴漏给子类的,子类重写才叫覆盖;
—因此两句话总结就是:
——重载:只看同名函数的参数列表。
——重写:子父类方法要一模一样。
————————————————————————————
————————————————————————————
子父类中的构造函数:
—在对子类进行初始化时,父类的构造函数也会运行,那是因为子类的构造函数默认第一行有一条隐式添加的执行语句,那就是“super();”,他叫访问父类中无参数的构造函数,而且子类中所有的构造函数默认第一行都是super“super();”。
—要注意:只是隐式调用父类无参的构造函数而已,有参的父类构造函数不会调用;
—当你写了一个类里面只放了一个有参的构造方法,那么Java编译的时候就默认这个类已经有构造方法,就不会帮你隐式的生成无参数的构造方法了,当你调用无参数的构造方法时就会被编译器报错。
————————————————————————————
为什么子列一定要访问父类中的构造函数:
—因为父类中的数据子类可以直接获取,所以子类对象在建立时,需要先查看父类是如何对这些数据进行初始化的。所以子类在对象初始化时候,要先访问一下父类中的构造函数。
—如果要访问父类中指定的构造函数,可以通过手动定义super语句的方式来指定。
总之记住:super语句一定定义在子类构造函数代码的第一行。
————————————————————————————
结论:子类的所有的构造函数,默认都会访问父类中空参数的构造函数。
—因为子类每一个构造函数内的第一行,都有一句隐式super();
—当父类中没有空参数的构造函数时,子类必须都手动通过super语句形式来指定要访问父类中的构造函数。
—当然子类的构造函数第一行也可以手动指定this语句来访问本类中的构造函数;
—总之,子类中至少会有一个构造函数会访问到父类中的构造函数;
————————————————————————————
————————————————————————————
final关键字
final关键字:作为一个修饰符,
—1.可以修饰类、函数、变量;
—2.被final修饰的类不能够被继承;为了避免被子类复写功能,加final,表示最终类,不能有子类;
—3.被final修饰的方法不能复写(final void show1(){…});
—4.被final修饰的变量,只能复赋值一次,既可以修饰成员变量,又可以修饰局部变量;
——当在描述事物时候,一些数据的出现值是固定的,那么这是为了增强代码阅读性,都给这些值起个名字,方便于阅读;而这个值不需要改变,所以加上final;作为常量的书写规范,所有字母大写,如果由多个单词组成,单词之间用下划线连接;
—5.内部类定义在类中的局部位置上时,只能访问该局部被final需要修饰的局部变量;
一般定义全局变量都这样写,比如定义一个double类型的PI,3.14159…:
——public static final double PI = 3.14159;
————————————————————————————
总结一下目前学习到的class,也就是类前面的修饰符,一共有三种:
—1.public,共有类——谁都可以用;
—2.什么都不写,默认权限,介于public 和private之间;
—3.final;让类不可被继承;
————————————————————————————
————————————————————————————
抽象类
接下来大家看看这个示例代码:
————————————————————————————
abstract class Person{ abstract void eat();}class Student{ void eat() { System.out.println("学生吃饭!"); }}class Worker{ void eat() { System.out.println("工人吃饭!"); }}
————————————————————————————
可以看到我们的类前面又多了一个新的修饰符,那就是“abstract”;
当我们的类中出现相同功能,但是功能主题不同的时候,这时可以进行向上抽取的,然而每个具体类的实现格式不一,因此我们可以选择之抽取功能定义,而不抽取功能主体(“{ }”之间的内容)。
而对于这种没有方法没有方法主题的方法必须使用一个关键字标识——abstract,抽象;
因为一个类中出现了抽象方法,因此这个类的这个可能不能够做一些事情,因此这个类也必须设置成抽象的,也必须使用“abstract”修饰,如代码中的“abstract class Person”。
抽象类的特点:
—1、抽象类和抽象方法必须用abstract关键字来修饰。
—2、抽象方法只有方法声明,没有方法体,定义在抽象类中。
——格式:修饰符abstract返回值类型 函数名(参数列表);
—3、 抽象类不可以被实例化,也就是不可以用new创建对象。原因如下:
—抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。例如:犬科是一个抽象的概念,真正存在的是狼和狗。 而且抽象类即使创建了对象,调用抽象方法也没有意义。
—4、抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类。
—注意1:抽象类中可以有非抽象的方法的。
—注意2:抽象类并不是依赖抽象方法*,也就是说抽象类中可以不定义抽象方法,这样做仅仅是不让该类创建对象;Java中是存在这种情况的*!
下面看一个实例代码:
————————————————————————————
/*假如我们在开发一个系统时需要对员工进行建模,员工包含 3 个属性:姓名、工号以及工资。经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。员工类:name id pay经理类:继承了员工,并有自己特有的bonus。*/class class Demo5_4{ public static void main(String[] args) { new Manager("manager","001",10000,2000).work(); new Pro("pro","020",5000).work(); } } //员工类,也是父类 abstract class Employee { private String name;//姓名 private String id; //工号 private double pay; //工资 //自定义构造函数初始化 Employee(String name,String id,double pay) { this.name = name; this.id = id; this.pay = pay; } public abstract void work();//抽象的工作方法 } //经理类,继承了员工类 class Manager extends Employee { private int bonus;//特有的奖金属性 Manager(String name,String id,double pay,int bonus)//子类的构造方法 { super(name,id,pay);//调用父(超)类中的构造器 this.bonus = bonus; } public void work()//经理类的工作方法内容 { System.out.println("manager work"); }}//普通员工类,继承员工类 class Pro extends Employee { Pro(String name,String id,double pay) { super(name,id,pay); } public void work()//普通员工类的工作方法内容 { System.out.println("pro work"); } }
————————————————————————————
学会了面向对象我们就又可以涉足一个设计模式,那就是模版方法设计模式:
—模板方法:定义功能的时候,功能的一部分确定的,一部分不确定的,确定的部分使用不确定的,那么这时候就将不确定的部分暴露出去,由该类的子类去完成;
—看下面的实例代码:
——需求:想要获取一个Program1程序run方法的运行时间;
————————————————————————————
class Program1//原来的程序,//现在有个需求就是想要获得这个类中run方法的运行时间{ public void run() { for(int i=0;i<100;i++) System.out.print(i); }}/** 而现在有这样一个能够获取时间的类*/abstract class GetTime{ public final void getTime() { //System类的currentTimeMillis();能够返回当前时间-去特定时间的毫秒值 long startTime = System.currentTimeMillis(); runCode(); long endTime = System.currentTimeMillis(); System.out.print("耗时 "+( endTime - startTime )+" 毫秒"); } public abstract void runCode();}class Demo{ public static void main(String[] args) { /*Program1 pro1 = new Program1(); pro1.run();*/ Program2 pro1 = new Program2(); pro1.getTime(); }}/**现在稍稍改写Program1为Program2,使其拥有获取时间的能力*/class Program2 extends GetTime{ public void run() { for(int i=0;i<100;i++) System.out.print(i); } public void runCode() { run(); }}
————————————————————————————
————————————————————————————
接口
如果一个抽象类中方法全部都是抽象的,那么还有一种专门的形式那就是接口;
—实际的原因当然不是这样的,但是这样说是为了理解,好让我们从抽象过渡到接口;
接口可以被认为是一个特殊的抽象类。当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。接口使用interface来表示,子类中用implements实现。格式为:
——————————————————————
interface 接口名{}
子类名 implements 接口名{}
——————————————————————
格式特点:
—①接口中常见定义:常量,抽象方法。
—②接口中的成员都有固定修饰符。
——常量:public static final
——方法:public abstract
—③接口中的成员都是public的。
—在使用中,常量可以不写publicstatic final,方法可以不写public abstract,编译时Java会自动添加这些修饰符,因为这是固定的格式修饰符。但为了增加代码阅读性,通常我们都写上。
———————————————————————————
类与类,类与接口关系:
—类与类继承,类与接口实现——implements
—因为通过集成拿到的都是抽象方法,因此都需要实现,如果不实现,那这个类就要标识抽象abstract;
—什么叫实现:只要写了方法体就算实现,也就是方法声明写完再加上”{ }“就等于将方法实现了。
————————————————————————————
**Java中虽然不能够多继承,但是接口可以被类多实现,也是对多继承的转换形式;;
而接口中都是抽象的方法,没有方法体,因此只要在实现类里面覆盖同名方法,就等于全部实现了接口中的所有同名方法了;
而且类可以继承一个类然后再实现多个接口,完成方法的扩展;
类与类继承关系,类与接口实现关系,接口与接口之间也是继承关系;
而且接口与接口可以多继承,如下;**
————————————————————————————
interface A
{}
interface B extends A
{}
interface C extends B
{}
——————————————————————
interface A
{}
interface B
{}
interface C extends A,B//多继承使用逗号分开
{}
————————————————————————————
**接口的最主要的作用就是:扩展功能,降低耦合性;
—就好比我们的笔记本,我们需要扩大硬盘,使用USB鼠标,在USB接口上插上就可以了,这里USB接口就好比我们接口,用于扩展功能,使得硬件和我们电脑不在紧密结合在一起不可分离,降低了耦合性;**
我么前面说过:
—类继承就是is a,你是我的一个;
—而接口实现就是like a,你像我;
——基本功能定义在类中,而扩展功能定义在接口中;
如下面的实例代码:
————————————————————————————
abstract class Person{ //每个人学习方式不一,因此抽象 public abstract void study(); public void sleep()//每个人都睡觉 { System.out.println("sleep!"); }}/*有的人会抽烟,因此抽烟就相当于一个扩展功能*/interface SmokePerson{ void smoke();}/*有的人会唱歌,因此唱歌也相当于一个扩展功能*/interface SingPerson{ void sing();}/*这个学生除了学习还会唱歌*/class Student1 extends Person implements SingPerson{ public void study() { System.out.println("Student1 study!"); } public void sing() { System.out.println("Student1 sing!"); }}/*这个学生除了学习还会抽烟/class Student2 extends Person implements SmokePerson{ public void study() { System.out.println("Student2 study!"); } public void smoke() { System.out.println("Student2 smoke!"); }}class Demo5_5{ public static void main(String[] arg) { Student1 s1 = new Student1(); Student2 s2 = new Student2(); s1.sleep(); s1.study(); s1.sing(); s2.sleep(); s2.study(); s2.smoke(); }}
————————————————————————————
————————————————————————————
多态
—定义:多态可以理解为事物存在的多种体现形态。
—例:动物中猫,狗。
——猫这个对象对应的类型是猫类型,如:猫 x = new猫(); 同时猫也是动物中的一种,也可以把猫称为动物。
——动物 y = new猫(); 那么动物就是猫和狗具体事物中抽取出来的父类型。父类型引用指向了子类对象。
—多态不仅在对象上体现,还在函数上体现,重载,和覆盖;而这里我们讲的是对象的多态性;
—1.多态的体现
——父类的引用指向了自己的子类对象(从开篇的小程序就能够有所体会);
——或者说 父类的引用也可以接受自己的子类对象;
—2.多态的前提
——必须类与类继承和实现;
——通常还有一个前提,存在方法覆盖;
——没有覆盖的方法不能用;
—3.多态的好处
——提高代码的扩展性
—4.多态的好处
——提高了扩展性,但是还能用父类的引用访问父类中的成员;
—5.多态的应用(从开篇的小程序就能够有所体会)
——见下面。
—6.多态的出现代码中的特点(多态使用的注意事项)
——见下面。
下面一则车能够体现多态如何提高代码扩展性的:
————————————————————————————
class Demo5_6{ public static void main(String[] args) { //Cat a = new Cat(); Animal a = new Cat(); methodEat(new Cat()); methodEat(new Dog()); methodEat(new Pig()); } /* 这个方法的参数是一个Animal类型, 而Cat Dog和Pig都继承了Animal类, 因此这个方法能够接受实例的范围就被扩展开了。这就是多态的作用! */ public void methodEat(Animal a) { a.eat(); }}abstract class Animal{ abstract void eat();}//=====================class Cat extends Animal{ public void eat()//实现父类eat方法 { sop("吃鱼"); } public void catchMouse()//自己特有方法 { sop("抓老鼠"); }}//---------------------------------class Dog extends Animal{ public void eat()//实现父类eat方法 { sop("啃骨头"); } public void watchHouse()//自己特有方法 { sop("看门"); }}//---------------------------------class Pig extends Animal{ public void eat()//实现父类eat方法 { sop("饲料"); } public void gongDi()//自己特有方法 { sop("拱地"); }}
————————————————————————————
多态的应用
沿用上面的实例代码:
Animal a = new Cat();//这里有一个类型提升,也叫向上转型(自动完成)
类似byte → int;
这时候我们是不能够调用Cat特有的方法catchMouse的;
a.catchMouse();//(错误)
如果想要猫的特有方法的时候应该强制将父类引用转成子类型,向下转型:
Cat c = (Cat)a;
c.catchMouse();//(正确)
————————————————————————————
另外:要注意不能够出现这种情况:
—————————————————————
Animal a = new Animal();
Cat c = (Cat)a;//不能够将父类实例对象转成子类对象
—————————————————————
多态中成员的特点
—多态的出现代码中的特点(多态使用的注意事项)
——在动态中成员函数的特点:
———在编译时期,参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有编译失败;
———在运行时期,参阅对象所属的类中是否有调用的方法。
——简单的总结:成员函数在多态调用时,编译看左边,运行看右边;
————————————————————
在多态中成员变量的特点:
——无论编译还是运行时,都参考左边(引用型变量所属的类)
在多态中,静态成员函数的特点:
——无论编译还是运行时,都参考左边;
下面用一则实例代码,来做个总结:
————————————————————————————
class Fu//父类{ static int num = 9; void metd1() { System.out.println("metd1"); } void metd3() { System.out.println("metd3"); } static void metd5() { System.out.println("metd5"); }}class Zi/*子类*/ extends Fu{ static int num = 7; void metd1() { System.out.println("metd1_z"); } void metd2() { System.out.println("metd2_z"); } static void metd5() { System.out.println("metd5_z"); }}public class Demo5_7 { public static void main(String[] args) { System.out.println("---------------多态的时候,对于非静态方法,"); System.out.println("---------------只能调用继承的或覆盖的方法,否则编译报错"); Fu f = new Zi(); f.metd1(); //f.metd2();//报错,因为父类没有metd2这个方法 f.metd3(); Zi z = new Zi(); z.metd1();//打印:metd1_z,调用自己的方法 z.metd2();//打印:metd2_z,调用自己的方法 z.metd3();//打印:metd3,调用继承自父类的方法 System.out.println("---------------若想要调用子类中的新方法即不是从父类覆盖"); System.out.println("---------------或者继承的方法的时候,必须向下转型"); ((Zi)f).metd2(); System.out.println("---------------多态时,调用静态成员变量,看引用变量的声明类"); System.out.println(f.num);//打印:9,而不是7,多态的时候父类中静态成员变量不会被覆盖 System.out.println(z.num);//打印:7 System.out.println(((Zi)f).num);//打印:7,当然,转型之后就相当于z.num System.out.println("---------------多态时,调用静态成员方法,也是看引用变量的声明类"); f.metd5();//打印:metd5,而不是metd5_z,多态的时候父类中静态成员方法不会被覆盖 z.metd5();//打印:metd5_z ((Zi)f).metd5();//打印:metd5_z }}
————————————————————————————
下面再用一个电脑的运行的实例代码,演示多态的实际应用:
————————————————————————————
/* 电脑的运行由主板控制,假设主板只是提供电脑运行,但是没有上网,听歌等功能。而上网、听歌需要硬件的支持。而现在主板上没有网卡和声卡,这时可以定义一个规则,叫PCI接口,只要符合这个规则的网卡和声卡都可以在主板上使用,这样就降低了主板和网卡、声卡之间的耦合性。 */// 接口PCI interface PCI { void open(); void close();}// 网卡实现接口class NetCard implements PCI { public void open() { System.out.println("NetCard_open"); } public void close() { System.out.println("NetCard_close"); }}// 声卡实现接口class SoundCard implements PCI { public void open() { System.out.println("SoundCard_open"); } public void close() { System.out.println("SoundCard_close"); }}class Mainboard { // 电脑运行 public static void run() { System.out.println("Mainboard_run"); } // 使用扩展功能 public static void usePCI(PCI p)// PCI p = new NetCard()//接口型引用指向自己的子类对象。 { if (!(p == null)) { p.open(); p.close(); } }}class Demo5_8 { public static void main(String[] args) { Mainboard m = new Mainboard(); // 电脑运行 m.run(); // 电脑上网 m.usePCI(new NetCard()); // 电脑听歌 m.usePCI(new SoundCard()); }}
————————————————————————————
实际应用还有很多,比如说我们深入后都会学习到的Hibernate框架,因为数据库的操作无非是连接、CRUD(增删改查)操作、关闭资源,将这些方法抽取出来,定义成接口规则,那么我们的数据库框架就随时能够更换了,只要满足接口规则。
————————————————————————————
上帝类Object
—Object类是所有Java中的类直接或者间接继承的父类,相当于上帝;
——因此可想而知,其中定义的方法必定是所有类都具备方法;
比如:equals方法,在Object类中这个方法已经实现好了,用于比对两个对象的方法,没有特殊要求的时候都没有必要复写的!
补充:
—Object的toString();方法返回:类名@哈希值(①),
—Object的hashCode();方法返回:整型哈希值(②),
——①和②并不一样,需要Integer.toHexString(整型哈希值);转换一下;因为①是16进制;
——因为java为每个类原生的toString方法返回的是个大家不理解的内容,因此通常开发都复写一下这个方法;
- 黑马程序员——005——面向对象②(封装、继承、多态)
- 黑马程序员—面向对象之封装、继承、多态
- 黑马程序员—面向对象封装继承多态
- 黑马程序员——面向对象三大特征(封装、继承、多态)
- 黑马程序员——java面向对象(封装、继承、多态)
- 黑马程序员——Java面向对象(二)之封装、继承、多态、接口等
- 黑马程序员——OC笔记之面向对象三大特征(封装、继承、多态)
- 黑马程序员——面向对象(上)— 类、对象、封装、继承、构造方法
- 黑马程序员——OC面向对象三大特性——封装,继承,多态。
- 黑马程序员——OC面向对象三大特性——封装,继承,多态。
- 黑马程序员-面向对象三大原则——封装、继承、多态
- 黑马程序员--OC面向对象的三大特征——封装、继承、多态
- 黑马程序员——面向对象的三个特征----继承、封装、多态
- 黑马程序员——OC语言基础:面向对象三大特性,封装、继承、多态
- 黑马程序员——JAVA面向对象的特性:封装,继承,多态
- 黑马程序员——Java基础---面向对象(封装、继承、多态)
- 黑马程序员—面向对象(static,封装,继承,多态,内部类,抽象类,接口)总结
- 黑马程序员——Java基础---深入理解面向对象(封装继承和多态)
- Qt资源
- crontab-用法
- android中控件的style中主题样式定义
- break label 用法
- TMDS的信号通道
- 黑马程序员——005——面向对象②(封装、继承、多态)
- Windowsserver2012搭建VPN Part1
- 【从零开始学NGUI 】 (十)Anchor
- 函数的指针如何说明、赋值、调用
- IndentationError: unexpected indent python
- 高效团队的基础:
- _beginthreadex()和CreateThread()的区别 为什么不用_beginthread()?
- Linux内核版本不同,导致找不到相关的头文件解决办法
- css3 transform transition 实现照片墙效果