黑马程序员-----面向对象的特性封装、继承、多态、抽象
2015-09-19 22:31
525 查看
------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------
1.面向对象的特性
1.1封装
1.1.1封装的特点
1.直接对外部暴露成员变量是很不安全的,这时可以将成员变量“私有化”,对外提供公有的 get和set方法;2.封装的好处:
1)隐藏实现细节,提供公共的访问方式
2)提高了代码的复用性
3)提高安全性。
3.封装的原则:
1)将不需要对外提供的内容都隐藏起来。
2)把属性隐藏,提供公共方法对其访问。
1.1.2封装的代码解释
/*封装:
表现:
1,函数就是一个最基本封装体。
2,类其实也是一个封装体。
从以上两点得出结论:
好处:
1,提高了代码的复用性。
2,隐藏了实现细节,还要对外提供可以访问的方式。便于调用者的使用。这是核心之一,也可以理解为就是封装的概念。
3,提高了安全性。
它也是面向对象思想的特征之一。
共有三个特征:封装,继承,多态。
举例:机箱。隐藏了办卡设备的细节,对外提供了插口以及开关等访问内部细节的方式。
*/
//描述人。Person
//属性:年龄。
//行为:说话:说出自己的年龄。
/*
总结:
类中不需要对外提供的内容都私有化,包括属性和行为。
selectSort(int[] arr)
{
swap(
}
bubbleSort(int[] arr)
{
swap(
}
private swap(int[] arr,int a,int b)
{
}
重点:以后再描述事物,属性都私有化,并提供setXxxgetXxx方法对其进行访问。
*/
class Person { //属性: private int age;//age就是被修饰为了private私有。也就是被隐藏了。这就是封装的一种体现。 //行为: void speak() { System.out.println("age="+age); } /* 年龄已被私有,错误的值无法赋值,可是正确的值也赋值不了,不行。 咋办,按照之前所学习的封装的原理,隐藏后,还需要提供访问方式。 通过方法的方式,让其他程序访问到,就可以了。更重要的是可以在方法中加入逻辑判断。 记住:对变量的访问操作有两个动作:赋值(设置 set),取值(获取 get) 所以,对私有的变量访问的方式就是 set变量 get变量--> setAge getAge */ //定义对age赋值的方法。 void setAge(int a) { //加入逻辑判断。 if(a>0 && a<130) age = a; else // System.out.println("对不起,您的年龄数值 "+a+" 是非法的。"); // throw new RuntimeException("对不起,您的年龄数值 "+a+" 是非法的。");//异常!一旦出现,程序结束。需要修正代码。 } //定义一个获取age值的方法。 int getAge() { return age; } } class PersonDemo { public static void main(String[] args) { //测试Person.class。 //创建对象。 Person p = new Person(); /* 赋值-20是可以的,因为age属性是int类型,但是确不符合现实生活中的事物。 怎么解决这个问题呢? 不让它访问就哦了。怎么在代码上实现呢?需要使用一个Java中的关键字也是一个修饰符 private(私有,权限修饰符) 记住:私有仅仅是封装的体现形式而已。 */ // p.age = -20;//age不能在person类以外的程序中直接访问了。 //演示对age设置和获取方法的体现。 p.setAge(-20); int a = p.getAge(); System.out.println("a="+a); // p.speak(); } }
1.2继承
1.2.1继承的特点
1,继承的好处。★★★★★2,Java中的单继承和多继承的区别,以及多继承的好处,为什么不直接支持?★★★★★
多继承好处:更加的扩展了子类的功能。这个机制非常好。
但是有弊端:导致调用多父类中的相同功能时,出现调用的不确定性。
3,对于继承体系,应该怎么学习?★★★★★
参阅顶层类,使用底层类。
4.使用关键字:extends
5.作用:代码重用。为多态提供了前提;
6.this和super的区别:
1).this:
1).在任何类中使用;
2).存储的是本类对象的引用;
3).可以访问本对象的成员变量、成员方法、构造方法;
2).super:
1).在子类中使用;
2).存储的是父类对象的引用;
3).可以访问父类对象的成员变量、成员方法、构造方法;
7.类的初始化过程:
加载class文件
堆中开辟空间
变量的默认初始化
变量的显示初始化
构造代码块初始化
构造方法初始化
成员变量-->构造代码块-->构造方法
8.Java中继承的特点:
1).Java中只能单继承;
2).Java中可以多级继承;
9.继承的好处和弊端:
好处:
1).代码复用
2).为多态提供了前提;
弊端:
1).由于继承,子类对父类产生了依赖;
1.2.2 继承的代码体现
/* //描述学生。 class Student { //属性。 String name; int age; //行为。 void study() { System.out.println("good good study"); } } //描述工人。 class Worker { //属性。 String name; int age; //行为 void work() { System.out.println("hard work"); } } */ /* 为了提高复用,只建立一份代码。 一个类只要和另一个类产生关系就可以了 关系:继承。 发现了获取到所需内容的同时也获取到不该具备的内容。 为什么? 发现原来这个两个类之间根本就不存在继承关系。 怎么解决呢? 找到学生和工人的共性类型。将需要提供复用的代码进行抽取。 定义到一个共性类型的类中。 Person name age。 怎么在代码体现中让学生和Person产生关系呢? 只要通过关键字 extends(继承) 就哦了。 */ class Person { String name; int age; } class Student extends Person//学生继承了Person 学生就是子类 Person就是父类(基类,超类) { void study() { System.out.println("good good study"); } } class Worker extends Person { void work() { System.out.println("hard work"); } } /* 面向对象 另一个特征:继承。 好处:提高了代码的复用性。让类与类产生了关系,给另一个特征 多态 提供了前提。 什么时候定义继承? 必须保证类与类之间有所属(is a)关系。 xxx是zzz中的一种。 苹果是水果中一种。狗是犬科中一种。 在Java中继承的体现: Java允许单继承。不直接支持多继承,将多继承进行其他方式的体现。 单继承:一个子类只能有一个父类。 多继承:一个子类可以有多个父类。 */
1.3抽象
1.3.1抽象特点
1,抽象类和抽象方法都需要被abstract修饰。抽象方法一定要定义在抽象类中。2,抽象类不可以创建实例,原因:调用抽象方法没有意义。
3,只有覆盖了抽象类中所有的抽象方法后,其子类才可以实例化。
否则该子类还是一个抽象类。
1.3.2抽象类的细节
1,抽象类一定是个父类?是的,因为不断抽取而来的。
2,抽象类是否有构造函数?
有,虽然不能给自己的对象初始化,但是可以给自己的子类对象初始化。
抽象类和一般类的异同点:
相同:
1,它们都是用来描述事物的。
2,它们之中都可以定义属性和行为。
不同:
1,一般类可以具体的描述事物。
抽象类描述事物的信息不具体
2,抽象类中可以多定义一个成员:抽象函数。
3,一般类可以创建对象,而抽象类不能创建对象。
3,抽象类中是否可以不定义抽象方法。
是可以的,那这个抽象类的存在到底有什么意义呢?仅仅是不让该类创建对象。
4.使用abstract关键字修饰;可以修饰“类”,可以修饰“成员方法”;
abstractclass A{
abstractvoid show();
}
5.“抽象类”的特点:
1).不能被实例化,只能用于被继承;
2).可以包含:成员变量、构造方法、成员方法、抽象方法;
3).可以不包含抽象方法;
6“抽象方法”的特点:
1).没有方法体;abstract void show();
2).必须被子类重写。除非子类也是个抽象类;
7子类继承抽象类使用关键字:extends,仍然是单继承;
8.一个子类继承了一个抽象类,必须实现抽象类中所有的抽象方法;
否则子类也必须是抽象的。
例如:
abstractclass A{
abstractvoid show();
}
classB extends A{ } //编译错误。类B不是抽象的,继承类抽象类必须重写抽象类中的所有抽象方法。
abstractclass B extends A{ } //编译通过。类B没有重写父类中的抽象方法,但类B是抽象的。
9.abstract关键字不能和哪些关键字共存:
1.private:抽象方法就是用来被子类重写的,而私有方法不能被子类重写;
2.final:抽象类和抽象方法就是用来被子类继承和重写的,而fianl类和final方法不能
被继承和重写;
3.static:static修饰的方法在没有任何对象的情况下就会被分配内存空间;而抽象方法
没有方法体,无法分配空间;
1.3.3抽象类代码体现
/*需求:公司中程序员有姓名,工号,薪水,工作内容。
项目经理除了有姓名,工号,薪水,还有奖金,工作内容。
对给出需求进行数据建模。
在问题领域中先找寻其中涉及的对象。
程序员
属性:姓名,工号,薪水
行为:工作
项目经理
属性:姓名,工号,薪水,奖金
行为:工作
这些对象是否有关系呢?因为发现了他们之间的共性,应该存在着关系。
可以将他们的共性向上抽取到共性类型:员工。
员工:
属性:姓名,工号,薪水
行为:工作
发现员工的工作内容本身就不具体。应该是抽象的,由具体的子类来体现的。
一定要动手!
*/
abstract class Employee { private String name; private String id; private double pay; /** 构造一个员工对象,一初始化就具备着三个属性。 */ public Employee(String name,String id,double pay) { this.name = name; this.id = id; this.pay = pay; } /** 工作行为。 */ public abstract void work(); } //具体的子类:程序员。 class Programmer extends Employee { public Programmer(String name,String id,double pay) { super(name,id,pay); } public void work() { System.out.println("code...."); } } //具体的子类:经理。 class Manager extends Employee { //特有属性。 private double bonus; public Manager(String name,String id,double pay,double bonus) { super(name,id,pay); this.bonus = bonus; } public void work() { System.out.println("manage"); } } class AbstractTest { public static void main(String[] args) { System.out.println("Hello World!"); } }
1.4多态
1.4.1多态的特点
体现:父类或者接口的引用指向了自己的子类对象。好处:提高程序扩展性。
弊端:不能使用子类对象的特有内容。
前提:1,必须有关系(继承,实现);2,覆盖。
转型:
向上转型:提高扩展性,隐藏子类型,不需要使用子类型的特有方法。
向下转型:需要使用子类型的特有内容,注意:一定要instanceof判断类型,避免ClassCastExceptio
记住:转型中,自始至终都是子类对象做着类型的变化。
多态调用中,成员的特点:
成员变量,成员函数,静态函数。
总结:
对于成员变量和静态函数,编译和运行都看左边。
对于成员函数,编译看左边,运行看右边。原因是函数有覆盖,而是是动态绑 定到当前对象上。
1.4.2多态代码
//多态 class Dog extends Animal { public void eat() { System.out.println("骨头"); } public void lookHome() { System.out.println("看家"); } } //描述猫 class Cat extends Animal { public void eat() { System.out.println("鱼"); } public void catchMouse() { System.out.println("抓老鼠"); } } //进行抽取。将共性的功能抽取到父类Animal中。 abstract class Animal { public abstract void eat(); }
/*
多态:
【体现】
父类的引用或者接口的引用指向了自己的子类对象。
Dogd = new Dog();//Dog对象的类型是Dog类型。
Animala = new Dog();//Dog对象的类型右边是Dog类型,左边Animal类型。
【好处】
提高了程序的扩展性。
【弊端】
通过父类引用操作子类对象时,只能使用父类中已有的方法,不能操作子类特有的方法。
【前提】
1,必须有关系:继承,实现。
2,通常都有重写操作。
【子类的特有方法如何调用呢?】
Animala = new Dog();//Animal是父类型,new Dog()是子对象。
但是父类型引用指向子类对象时,这就是让子类对象进行了类型的提升(向上转型)。
向上转型好处:提高了扩展性,隐藏了子类型。弊端:不能使用子类型的特有方法。
如果要想使用子类的特有方法,只有子类型可以用。
可以向下转型,强制转换。
Animala = new Dog();
a.eat();
Dogd = (Dog)a;//将a转型为Dog类型。向下转型。
d.lookHome();
向下转型什么时候用?当需要使用子类型的特有内容时。
注意:无论向上还是向下转型,最终都是子类对象做着类型的变化。
【向下转型的注意事项】
Animala = new Dog();
//Catc = (Cat)a;向下转型因为不明确具体子类对象类型,所以容易引发ClassCastException异常。
所以为了避免这个问题,需要在向下转型前,做类型的判断。
判断类型用的是关键字 instanceof
if(ainstanceof Cat)//a指向的对象的类型是Cat类型。
{
//将a转型Cat类型。
Catc = (Cat)a;
c.catchMouse();
}
elseif(a instanceof Dog)
{
Dogd = (Dog)a;
d.lookHome();
}
【转型总结】
1,什么时候使用向上转型呢?
提高程序的扩展性,不关系子类型(子类型被隐藏)。
需要用子类的特有方法吗?不需要,哦了。向上转型。
2,什么时候使用向下转型呢?
需要使用子类型的特有方法时。
但是一定要使用 instanceof 进行类型的判断。避免发生ClassCastException
*/
class DuoTaiDemo2 { public static void main(String[] args) { Dog d = new Dog(); // d.eat(); // d.lookHome(); /* Animal a = new Dog(); a.eat();//可以的。 // a.lookHome();//不可以的。 */ method(d); Cat c = new Cat(); method(c); } public static void method(Animal a) { a.eat(); // Dog d = (Dog)a;//ClassCastException:类型转换异常。 // d.lookHome(); // a.lookHome();//不可以,因为动物不具备这个功能。 } }
1.4.3多态成员的特点
/*多态中,成员调用的特点。
1,成员变量。
当子父类中出现同名的成员变量时。
多态调用该变量时:
编译时期:参考的是引用型变量所属的类中是否有被调用的成员变量。没有,编译失败。
运行时期:也是调用引用型变量所属的类中的成员变量。
简单记:编译和运行都参考等号的左边。
编译运行看左边。
2,成员函数。
编译,参考左边,如果没有,编译失败。
运行,参考右边的对象所属的类。
编译看左边,运行看右边。
对于成员函数是动态绑定到对象上。
3,静态函数。
编译和运行都参考左边。
静态函数是静态的绑定到类上。
【结论】
对于成员变量和静态函数,编译和运行都看左边。
对于成员函数,编译看左边,运行看右边。
*/
class Fu { int num = 3; void show() { System.out.println("fu show run"); } static void method() { System.out.println("fu static method run"); } } class Zi extends Fu { int num = 5; void show() { System.out.println("zi show run.."); } static void method() { System.out.println("zi static method run"); } } class DuoTaiDemo3 { public static void main(String[] args) { /* //测试成员变量的多态调用。 Fu f = new Zi(); System.out.println(f.num);//3 Zi z = new Zi(); System.out.println(z.num);//5 */ /* //测试成员函数的多态调用。 Fu f = new Zi(); f.show(); */ //测试静态函数的多态调用。 Fu f = new Zi(); f.method(); //注意:真正开发静态方法是不会被多态调用的,因为静态方法不所属于对象,而是所属于类。 Fu.method(); Zi.method(); } }
/* 阶段一需求:笔记本电脑运行。 按照面向对象的思想,用代码体现。 名称提炼法。 笔记本电脑。 行为:运行。 class NoteBook { //运行功能。 public void run() { System.out.println("notebook run"); } } 阶段二需求:想要在笔记本电脑上加上一个手握式鼠标。 多了个对象:鼠标。 行为:开启,关闭。 class Mouse { public void open() { System.out.println("mouse open"); } public void close() { System.out.println("mouse close"); } } 笔记本怎么用鼠标呢? 在笔记本中多一个使用鼠标的功能。 需要修改原来的笔记本类中的内容,添加一个功能。 class NoteBook { //运行功能。 public void run() { System.out.println("notebook run"); } // 使用鼠标功能。 public void useMouse(Mouse m) { if(m!=null) { m.open(); m.close(); } } } //问题:如果想要加入一个键盘呢? 只要描述一个键盘类,并在电脑类中加入一个使用键盘的功能就哦了。 但是发现从鼠标开始这个问题就已经产生了,一旦需要添加新设备的时候, 都需要改变电脑的源码。这个扩展性是非常差的。 设计上该如何改进呢? 之前的问题在于外围设备的增加和笔记本电脑之间的耦合性过高。 如何降低外围设备和笔记本电脑的耦合性呢? 外围设备还不确定,我们不要面对外围具体设备。 为了让笔记本可以使用这些设备,可以事先定义好一些规则, 笔记本只要使用这些规则就可以了。 有了这些规则就可以进行笔记本的功能扩展。 后期这些外围设备只要符合这些规则就可以被笔记本使用了。 那么规则在java中该如何体现呢?接口。 //1,描述接口。USB。 //2,描述笔记本电脑:运行功能,使用USB接口的功能。 */ //USB接口定义。 interface USB { void open(); void close(); } //描述笔记本电脑。 class NoteBook { public void run() { System.out.println("notebook run"); } //使用usb接口的功能。 public void useUSB(USB usb)//接口类型的变量。接口类型的变量指向自己的子类对象。 //USB usb = new Mouse(); { if(usb!=null) { usb.open(); usb.close(); } } } //需要鼠标 。想要被笔记本电脑使用,该鼠标必须符合规则。 //描述鼠标。 class Mouse implements USB { public void open() { System.out.println("mouse open"); } public void close() { System.out.println("mouse close"); } } class KeyBoard implements USB { public void open() { System.out.println("KeyBoard open"); } public void close() { System.out.println("KeyBoard close"); } } /* 发现,接口的出现, 1,扩展了笔记本电脑功能。 2,定义了规则。 3,降低了笔记本电脑和外围设备之间的耦合性。 */ class DuoTaiTest2 { public static void main(String[] args) { NoteBook book = new NoteBook(); book.run(); book.useUSB(null); book.useUSB(new Mouse()); book.useUSB(new KeyBoard()); } }
相关文章推荐
- 黑马程序员-----多线程
- 黑马程序员-----反射技术
- 初入职场之心态和为人处世
- 初入职场必备技能
- 黑马程序员之---C学习笔记之printf与scanf使用及注意事项
- 网易面试总结
- 黑马程序员--C 语言学习笔记之简介
- Java基础知识强化47:StringBuffer类之StringBuffer的三个面试题
- 搜狐面试总结
- 操作系统常见面试题
- 黑马程序员——java笔记(多线程+Runnable接口)-第22天
- 打造eBox生态圈
- 前端面试题
- java面试遇到问题二 ------java编程语言的特点
- java面试遇到的问题一 -----面向对象的特点
- 轻松搞定面试中的二叉树题目
- 十道海量数据处理面试题
- Java基础知识强化31:String类之String的面试题
- JSP学习笔记(十):面试题2
- java从0单排之<<java就业培训教程>>复习与面试题回顾——01