本章主要讲解Java中面向对象的三大基本特征,即继承、封装、多态,希望通过本篇文章可以帮助小伙伴们更好的理解这些概念
我们程序设计追求“高内聚,低耦合”
高内聚:类的内部数据操作细节自己完成,不允许外部干涉
低耦合:仅对外暴露少量的方法用于使用。
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露岀来。这就是封装性的设计思想。
当我们创建一个类的对象以后,我们可以通过"对象.属性"的方式,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和存储范围的制约。除此之外,没其他制约条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如:setName()同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值。则需要将属性声明为私有的(private)。此时,针对于属性就体现了封装性。
体现一:
将类的属性xxx私化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值
private double radius;
public void setRadius(double radius){
this.radius = radius;
}
public double getRadius(){
return radius;
}
体现二:不对外暴露的私有的方法
体现三:单例模式(将构造器私有化)
体现四:如果不希望类在包外被调用,可以将类设置为缺省的。
通过对不同的方法属性设置不同的权限修饰符来达到对类进行封装的目的。
权限修饰符可用来修饰的结构说明:
class A extends B{
}
* A:子类、派生类、subclass
* B:父类、超类、基类、superclass
判断是否要进行继承:A is a B,若成立,则B继承A
子类A继承父类B以后,子类A中就获取了父类B中声明的所有的属性和方法。特别的,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私的结构。只因为封装性的影响,使得子类不能直接调用父类的结构而已。
子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。子类和父类的关系,不同于子集和集合的关系。
是Java中所有类的父类,类似于二叉树中的根节点,定义了一些通用的方法。
属性:无
方法:equals() / toString() / getClass() /hashCode() / clone() / finalize()
wait() 、 notify()、notifyAll()
public boolean equals(Object obj) {
return (this == obj);
}
使用说明:
手动重写举例:
class User{
String name;
int age;
//重写其equals()方法
public boolean equals(Object obj){
if(obj == this){
//判断形参和比较对象的引用地址是否相同,相同直接返回true
return true;
}
if(obj instanceof User){
User u = (User)obj;
return this.age == u.age && this.name.equals(u.name);
}
return false;
}
}
自动生成的,自动生成快捷键ctrl+alt+S,选择自动生成hashCode和equals方法
自动生成的代码:
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
//Java开发交流君样:673927155
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
回顾 == 运算符的使用:
== :运算符
1.可以使用在基本数据类型变量和引用数据类型变量中
2.如果比较的是基本数据类型变量:
比较两个变量保存的数据是否相等。(不一定类型要相同)
3.如果比较的是引用数据类型变量:
比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
使用说明
toString()的使用:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
3.像String、Date、File、包装类等都重写了Object类中的toString()方法。使得在调用对象的toString()时,返回"实体内容"信息。
4.自定义类也可以重写toString()方法,当调用此方法时,返回对象的"实体内容"
重写toString()
//自动实现
@Override
public String toString() {
return "Customer [name=" + name + ", age=" + age + "]";
}
子类继承父类以后,就获取了父类中声明的属性或方法。 创建子类的对象,在堆空间中,就会加载所父类中声明的属性。
当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,…直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所的父类的结构,所以才可以看到内存中父类中的结构,子类对象才可以考虑进行调用。
虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。
可以理解为一个事物的多种形态。比如数据库的连接方式,我们定义好了数据库的连接,也规定了连接时的步骤,但是我们并不知道用户会采用什么数据库,在没有多态以前我们只能针对不同的数据库写不同的连接方法,而有了多态以后我们只需要定义好数据库的类并书写好连接方法,让所有的数据库继承数据库类并重写数据库连接方法。
这样我们在调用的时候只需要通过声明数据库类并指向数据库的子类的方式,**(即数据库类的引用指向继承了数据库类的具体实现类的对象)**就可以进行数据库连接。而不是需要针对不同的数据库书写不同的连接方式。
对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
编译时和运行时类型不一致,产生了多态
代码举例
Person p = new Man();
Object obj = new Date();
一个变量只能有一种确定的数据类型
一个引用类型变量可能指向(引用)多种不同类型的对象
① 类的继承关系 ② 方法的重写
举例一:
public void func(Animal animal){
//Animal animal = new Dog();
animal.eat();
animal.shout();
}
举例二:
public void method(Object obj){
}
举例三:
class Driver{
public void doData(Connection conn){
//conn = new MySQlConnection(); / conn = new OracleConnection();
//规范的步骤去操作数据
//Java开发交流君样:673927155
// conn.method1();
// conn.method2();
// conn.method3();
}
}
对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)
个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法
多态的作用:提高了代码的通用性,常称作接口重用
使用前提:①需要存在继承或者实现关系 ②有方法的重写
成员方法:
编译时:要查看引用变量所声明的类中是否有所调用的方法
运行时:调用实际new的对象所属的类中的重写方法
向上转型:多态
有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。如何才能调用子类特的属性和方法?使用向下转型。
使用强制类型转换符:()
Person p = new Man();
Man m1=(Man)p2;//向下转型
① 使用强转时,可能出现ClassCastException的异常。
② 为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
③ 只有对象A是B的子类实例化对象或者在下层的子类,才能向下转型
① a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
② 如果 a instanceof A返回true,则 a instanceof B也返回true.其中,类B是类A的父类。
③ 要求a所属的类与类A必须是子类和父类的关系,否则编译错误。
p instanceif Man//左边是变量名,右边是类的类型
1.实现代码的通用性。
2.举例:
class Base {
int count = 10;
public void display() {
System.out.println(this.count);
}
}
class Sub extends Base {
int count = 20;
public void display() {
System.out.println(this.count);
}
}
public class FieldMethodTest {
public static void main(String[] args) {
Sub s = new Sub();
System.out.println(s.count);//20
s.display();//20
Base b = s;//多态性
//Java开发交君样:673927155
//==:对于引用数据类型来讲,比较的是两个引用数据类型变量的地址值是否相同
System.out.println(b == s);//true
System.out.println(b.count);//10
b.display();//20
}
}