估计学过面向对象的伙伴,对面向对象的三种属性应该都知道这么个事,今天突然兴起,想总结一下,因为大学本科学的基本都还给老师了。
面向对象有三大属性:
封装、继承、和多态。
我们接下来一个一个记录:(参考前人博客)
封装:首先是抽象,把事物抽象成一个类,其次才是封装,将事物拥有的属性和动作隐藏起来,只保留特定的方法与外界联系,封装就是将属性私有化,提供公有的方法访问私有属性。
为什么要封装?
①隐藏实现细节。
好比你买了台电视机,你只需要怎么使用,并不用了解其实现原理。
②安全性。
比如你在程序中私有化了age属性,并提供了对外的get和set方法,当外界 使用set方法为属性设值的时候 你可以在set方法里面做个if判断,把值设值在0-80岁,那样他就不能随意赋值了。
③增加代码的复用性。
好比在工具类中封装的各种方法,你可以在任意地方重复调用,而不用再每处都去实现其细节。
④模块化。
封装分为属性封装,方法封装,类封装,插件封装,模块封装,系统封装等等。
有利于程序的协助分工,互不干扰,方便了模块之间的相互组合与分解,也有利于代码的调试和维护。比如人体由各个器官所组成,如果有个器官出现问题,你只要去对这个器官进行医治就行了。
public class Human
{
private int age;
private String name;
public int getAge()
{
return age;
}
public void setAge( int age ) throws Exception
{
//封装age的检验逻辑,而不是暴露给每个调用者去处理
if( age > 120 )
{
throw new Exception( "Invalid value of age" );
}
this.age = age;
}
public String getName()
{
return name;
}
public void setName( String name )
{
this.name = name;
}
}
如上所示:我们给Human这个类设置了set和get的方法,属性值设置为private,也就说外面的类是访问不到的(直接访问),他们只能根据set和get方法来访问。
继承
从已知的一个类中派生出新的一个类,叫子类。子类实现了父类所有非私有化属性和方法,并能根据自己的实际需求扩展出新的行为。
为什么要继承?
①继承是传递的,容易在其基础上构造,建立和扩充出新的类。
②简化了人们对事物的认识和描述,能清晰体现相关类之间的层次结构关系。
③能减少数据和代码的冗余度。
④大大增加了代码的维护性。
Java的类可以分为三类:
- 类:使用class定义,没有抽象方法
- 抽象类:使用abstract class定义,可以有也可以没有抽象方法
- 接口:使用inerface定义,只能有抽象方法
在这三个类型之间存在如下关系:
- 类可以extends:类、抽象类(必须实现所有抽象方法),但只能extends一个,可以implements多个接口(必须实现所有接口方法)
- 抽象类可以extends:类,抽象类(可全部、部分、或者完全不实现父类抽象方法),可以implements多个接口(可全部、部分、或者完全不实现接口方法)
- 接口只能extends一个接口
继承以后子类可以得到什么:
- 子类拥有父类非private的属性和方法
- 子类可以添加自己的方法和属性,即对父类进行扩展
- 子类可以重新定义父类的方法,即多态里面的覆盖,后面会详述
关于构造函数:
- 构造函数不能被继承,子类可以通过super()显示调用父类的构造函数
- 创建子类时,编译器会自动调用父类的 无参构造函数
- 如果父类没有定义无参构造函数,子类必须在构造函数的第一行代码使用super()显示调用
注意:类默认拥有无参构造函数,如果定义了其他有参构造函数,则无参函数失效,所以父类没有定义无参构造函数,不是指父类没有写无参构造函数。看下面的例子,父类为Human,子类为Programmer
public class Human
{
//定义了有参构造函数,默认无参构造函数失效
public Human(String name)
{
}
}
public class Programmer
extends Human
{
public Programmer()
{
//如不显示调用,编译器会出现如下错误
//Implicit super constructor Human() is undefined. Must explicitly invoke another constructor
super( "x" );
}
}
多态
多态的概念:多个不同的对象对同一消息作出响应,同一消息根据不同的对象而采用各种不同的行为方法。
多态的好处:主要是利于扩展。直接上代码自己来体会。
(1)同一个引用类型,使用不同的实例(对象)而执行不同的操作,是具体根据实例(对象)来确定调用相应的方法
(2)多态的条件:
a 继承是多态的基础,继承是必要条件
b 方法重写
c 父类引用指向子类对象
(3)多态的好处:提高程序的可扩性以及维护性,实际应用中,新增一个子类就相当于一个新的需求,测试类相当于业务的逻辑实现
(4)没有使用多态前的解决方案:
a 新建一个子类
b 在主人类中增加一个喂新增子类的方法
c 在测试类中去实例化(创建)子类的对象以及主人类实例化(创建)对象
class Human
{
public void showName()
{
System.out.println( "I am Human" );
}
}
//继承关系
class Doctor
extends Human
{
//方法重写
public void showName()
{
System.out.println( "I am Doctor" );
}
}
class Programmer
extends Human
{
public void showName()
{
System.out.println( "I am Programmer" );
}
}
public class Test
{
//向上转型
public Human humanFactory( String humanType )
{
if( "doctor".equals( humanType ) )
{
return new Doctor();
}
if( "programmer".equals( humanType ) )
{
return new Programmer();
}
return new Human();
}
public static void main( String args[] )
{
Test test = new Test();
Human human = test.humanFactory( "doctor" );
human.showName();//Output:I am Doctor
human = test.humanFactory( "programmer" );
human.showName();//Output:I am Programmer
//一个接口的方法,表现出不同的形态,意即为多态也
}
}