什么是面向对象?
面向对象程序设计以一种反应真实世界的方式组织程序,在真实世界中,所有对象的属性及动作都是相互关联的。使用对象提高了软件的可重用性,并且使程序更易于维护和开发,一个java程序可以看做是一个相互操作的对象的集合。
也就是说,面向对象编程其实就是在模拟一个真实的世界,只不过其表现形式是代码而已。使用面向对象思想进行编程的程序员就是“上帝”,我国上古神话中有女娲造人的故事,女娲在捏土造人中,先是单个捏出几个“人”,后来使用藤条以之前早出的人为模型大规模造人。在面向对象的世界中,程序员这个“上帝”抽象其身处的现实世界,在代码中创造出其模板(也就是类),之后以模板来创造对象。
就像现实世界中你不可能直接通过看就知道别人的信息一样,在代码实现中,这种行为同样的不允许的,也就是说其他对象不能直接访问或修改其他对象的属性(成员变量),对象的属性对外是隐藏的,要访问这些数据,只能通过相应的开放的方法进行访问。这就是封装(数据隐藏)。
面向对象同样模拟现实世界中各种事物之间的关系(根据需要),这就是继承和组合,(如父子继承关系中,儿子可以获得父亲传授给他的技能及资产,而表现在面向对象中,就是子类可以继承父类开放的属性和方法),同样,一个人可以有不同的身份,物品有不同的使用场景等等,表现在代码的世界就是多态。
面向对象的特征
封装(数据隐藏)
封装:实现封装的关键在于绝对不能让类中的方法直接访问其他类域的数据,程序仅仅能够通过对象的方法来实现与对象数据的交互。
这使得类可以全面的改变存储、操作数据的方式,而在外部,只要仍旧使用同样的方法,其他对象不会知道或介意其内部发生的具体变化。
封装思想:
1) 将类的属性私有化,避免对数据域的直接修改、
2) 提供公共的方法(getter & setter)实现调用、
3) 使得类易于维护、
权限修饰符:
应该总是将类的成员变量设为private,以保持良好的封装
继承
继承: 已存在的类复用继承类的方法和域,同时可以扩展自己的新的方法和成员变量
继承表示一种is-a关系
is-a:子类的每个对象也是超类的对象。其另一种表述方法就是置换法则,它表明程序中出现超类对象的任何地方都能够用子类对象置换。
比如说Student继承Person,则说明Student is a Person
继承的优缺点 | … |
---|---|
优点 | 子类可以重写父类的方法来方便地实现对父类的扩展 |
缺点 | 父类的内部细节对子类是可见的。 |
缺点 | 子类从父类继承的方法在编译时就确定下来了,所以无法在运行期间改变从父类继承的方法的行为 |
缺点 | 如果对父类的方法做了修改的话(比如增加了一个参数),则子类的方法必须做出相应的修改。所以说子类与父类是一种高耦合,违背了面向对象思想 |
java继承的方式
java语言只支持单继承,一个类只能有一个父类,但一个父类可以有任意多个子类,也就是,尽管java语言只支持单继承,但是支持多层继承。
在继承层次中,从某个特定的类到其祖先的路径称为继承链
public class Parent {...}
// java只支持单继承
public class Child extends Parent {...}
// 但java支持层继承
public class GrandSon extends Child {...]
注意:接口与接口之间也是继承关系
public interface Tools {...}
public interface Hatchet extends Tools {...}
注意: 尽管继承自同一个父类,但是其兄弟类之间没有任何关系
构造器不能被继承
方法的重写
当子类继承一个父类时,就可以同时继承基类公开的方法,同时子类可以对父类的功能进行扩展
子类继承自父类的方法对子类不适用时,子类可以重写父类的方法(Override)
方法重写规则:
- 要求子类重写父类的方法”返回值类型、方法名、参数列表”与父类方法保持一致
- 子类重写的方法权限修饰符不能小于(大于等于)父类方法的权限修饰符
- 若父类方法抛异常,那么子类重写方法抛的异常不能大于父类(也可以不抛)
- 子类与父类的方法必须同为static或非static(静态只能覆盖静态)
方法重写和重载有什么区别?
方法的重写用于当子类继承自父类的方法对子类不适用时,除权限修饰符外,返回值类型,方法名和参数列表都是相同的。
重载用在同一个类中各方法方法名相同,参数列表不同(与返回值类型没有关系)的情况
多态
多态:一个对象变量可以指示多种实际类型的现象称为多态,父类类型可以指示它所有的子类类型,而在程序运行时,
可以自动的选择调用哪个方法的现象称为动态绑定。
在 OOP 中最常用的多态性发生在当父类引用指向孩子类对象时,可以理解为一个事物的多种形态
注意:只在调用方法时才有动态绑定,当调用成员变量时,声明时是哪个类,则调用哪个类中的成员变量,若没有,则向该类的父类查找,没有则报错
例如:现实的事物经常为出现多种形态,比如现实中的人,在家是父亲、儿子、丈夫,到公司是员工、经理、老板等,到学校又可以是老师、学生等,在不同的场合一个人会有不同身份(状态)的转变,与之对应的就会有不同的行为(方法)
也就是说,尽管在声明时,使用父类类型A指示了子类类型B实例化的对象,但是在程序运行时,该对象所调用的方法依旧是其实际类型中的方法,也就是类B中定义的方法)
子类对象的多态性使用的前提:
- 要有类的继承
- 要有子类对父类的重写
多态下访问成员变量及方法的特点:
- 访问成员变量:编译看左边,运行看左边
- 访问成员方法:编译看左边,运行看右边
示例代码:
public class Parent {
String test = "Parent";
public void test() {
System.out.println("Parent Test...");
}
}
public class Child extends Parent {
String test = "Child";
public void test() {
System.out.println("Child Test...");
}
}
public class Test {
public static void main(String[] args) {
// 多态
Parent p = new Child();
// 访问成员变量:编译看左边,运行看左边
String str = p.test;
System.out.println(str); // Parent
// 动态绑定
// 访问成员方法:编译看左边,运行看右边
p.test(); // Child Test...
}
}
若方法用private、static或final修饰,或者为构造器方法,则采用静态绑定。
多态下访问静态成员变量及静态方法的特点:
- 访问成员变量:编译看左边,运行看左边
- 访问成员方法:编译看左边,运行看左边
静态变量或静态方法属于类而不属于对象,不推荐使用引用变量调用相应类的静态方法或变量。
package com.tennyson.test.oop;
public class StaticTest {
public static void main(String[] args) {
Parent p = new Child();
String message = p.car;
System.out.println(message); // Parent'Car
p.test(); // Parent's Test
}
}
class Parent {
static String car = "Parent's Car";
public static void test() {
System.out.println("Parent's Test");
}
}
class Child extends Parent {
static String car = "Child's Car";
public static void test() {
System.out.println("Child's Car");
}
}
java程序设计中,对象变量是多态的,其既可以引用它本身的类型,也可以引用所有它的子类的类型,但是不能够将超类的引用赋值给子类变量。
程序运行分为编译状态和运行状态
对于多态性,在编译时,”看左边”,将此变量理解为父类的类型
在运行时,”看右边”,关注于真正对象的实体:子类的对象,那么执行的方法就是子类重写的
public class Test{
public static void main(String[] args){
Parent p = new Child(); // 编译时将此变量看做是Father类型
}
}
class Parent{
...
}
class Child extends parent{
...
}
子类对象的多态性,并不适用于属性(属性没有多态性)
向上转型和向下转型
向上转型 –> 自动转换
就如同一条狗,也可以笼统的说它是动物,不用强制转换,事实如此,表现在java中即为向上转型:
Animal a = new Dog(); // 向上转型
但如果直接说一个动物,就是一条狗,是欠妥的,若它本身是一条狗,则可以实现这种转换:
Animal a = new Dog();
Dog d = (Dog) a; // 向下转型
从这个角度,也可以解释了java中,当以父类型变量引用一个子类时,子类特有的方法不能使用。不同角色有其独特的方法,当你表现为什么方法时,就只能使用当前身份所拥有的方法
instanceof
对象 instanceof 类名
该关键字用于检测一个对象是否是某种类型 返回布尔值