在学习面向对象的三大特性时也会产生一些困难,我在学习时虽然很清楚明白面向对象编程的三大特性是:封装,继承,多态。但对于书本之中的生硬的概念,确实不好理解,但多敲代码多练习一定会有新收获的,我现在可以把现阶段我理解的内容写出来,以后随时有了更深的理解也会更新。
- 封装
那就先说封装吧,封装就是将类的某些信息隐藏在类的内部,不允许外部程序直接进行访问,而是通过该类提供的方法进行操作和访问。那么封装的优点在于哪里呢?
不能随意对类的属性进行访问了,如果我的类中属性有初值并且不希望这个值被改变,那么封装起来之后是不会被直接访问的;而是只能通过方法对属性进行访问,这样双方的要求就都会得到满足。并且我可以随时修改我所写的类属性的名称,完全不影响其余代码,其实我们在使用一个类的时候并不关心这个类是如何实现方法的,我们只是想使用它而已,(可以参考《Java核心技术卷一第十版》p109的例子)
实现封装有三个步骤
- 将属性改为私有的;
- 创建公共的getter/setter方法;
- 给getter/setter中添加控制属性的语句;
用代码进行实现:
首先完成第一步,将属性改为私有
//定义手机的属性,手机屏幕大小与cpu
private double screen = 6.0;
private String cpu = "麒麟980";
完成二,三步,创建setter和getter方法并添加控制属性的语句
public double getScreen() {
return screen;
}
public void setScreen(double screen) {
this.screen = screen;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
好了,现在在Demo类中演示一下如何使用setter和getter方法
//构造一个手机类的对象tel
Telephone tel = new Telephone();
//通过setter和getter方法实现对象访问属性
tel.setScreen(5.0);
tel.setCpu("A11");
System.out.println("该手机的屏幕大小是:" + tel.getScreen() );
System.out.println("该手机的CPU型号是:" + tel.getCpu());
最后我们运行程序可以得到结果
不难看出我在给属性赋值时,并没有改变属性原有的值,这就是使用setter/getter方法的好处,也是封装的优点
- 继承
继承是Java的第二大特性,继承是类与类之间的一种关系,也就是 is a 的关系,举个例子,狗是动物就可以看成狗类继承动物类,狗类就是动物类的子类或派生类,而动物类即是狗类的父类或基类或超类,需要注意的是Java中的继承是单继承
那么继承的优点在于哪里呢?在Java中如果一个类继承了另一个类,那么这个子类就拥有了父类的所有方法和属性(private修饰的属性和方法除外)这样就实现了代码的复用,实现继承很简单,只需要使用extends关键字,以下是代码示例
public class Dog extends Animals{
}
在子类继承了父类之后,如果子类对于父类的某个方法不满意,那么还可以重写(覆盖)父类的方法,对象调用方法时会优先调用子类的方法。实现覆盖需要有三个条件
- 与父类的方法名相同
- 参数个数与类型相同
- 返回值类型相同
刚才提到了private,那么就说一下public protected 缺省 private四种修饰符的访问权限
(由于我们的方法就是创造出来想被使用的,所以一般方法的修饰符用public修饰,而属性一般不想任意被修改,所以基本用private修饰)
本类 | 同包 | 子类 | 所有类 | |
---|---|---|---|---|
private | 可以 | |||
缺省 | 可以 | 可以 | ||
protected | 可以 | 可以 | 可以 | |
private | 可以 | 可以 | 可以 | 可以 |
以下就用代码来看看刚才举的例子吧!先创建一个动物类和狗类
public class Animals {
//定义动物类的属性
private int age;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//创建一个方法表示动物类有吃这个方法
public void eat(){
System.out.println("动物可以吃");
}
}
//狗类
public class Dog extends Animals{
//重写父类的eat方法
public void eat(){
System.out.println("狗具有吃的能力");
}
}
创建Demo类进行演示
public class Demo {
public static void main(String[] args) {
// TODO Auto-generated method stub
//构造Dog类的对象dog
Dog dog = new Dog();
//dog对象可以调用父类中的方法为属性赋值
dog.setAge(3);
dog.setName("小白");
System.out.println("狗的年龄是" + dog.getAge() + "岁,它的名字是" + dog.getName());
//dog对象调用自己类中的重写方法
dog.eat();
}
}
- 多态
多态的意思就是对象具有多种形态,主要从两方面来讲,引用多态和方法多态
引用多态:一个类的引用可以指向本类对象,这时基本的,并且之前的例子也都是这么做的,那么因为引用多态的这个特性,父类的引用也可以指向子类的对象(注意:子类的引用不可以指向父类的对象),接着在刚才创建的Demo类中做一下尝试
//引用本类构造本类的对象
Animals dog1 = new Animals();
//引用子类构造父类的对象
Animals dog2 = new Dog();
//这样引用父类构造子类对象是不可以的,会报错
Dog dog3 = new Animals();
方法多态:创建一个本类对象,对象调用的方法就是本类的方法,如果引用父类创建的子类对象那么对象调用的方法就是子类重写的方法(如果子类没有重写这个方法,那么调用的还是父类方法),再接着用刚才的代码做演示
//引用本类构造本类的对象
Animals dog1 = new Animals();
//引用子类构造父类的对象
Animals dog2 = new Dog();
dog1.eat();
dog2.eat();
(还有一点需要注意,如果是子类独有而父类没有的方法,那么引用父类创建的子类对象就不可以调用这个方法)
类型转换分为向上类型转换(子类对象转换为父类对象)和向下类型转换(父类对象转换为子类对象),向上类型转换也可以叫做自动转换,无风险,不会出现问题,向下类型转换也就是强制类型风险,不会出现问题,向下类型转换也就是强制类型转换,会有风险,所以强制转换之前需要先进行一个判断,用来判断有无风险的关键字就是instanceof
Dog dog4 = new Dog();
//自动类型转换,无风险
Animals animal = dog4;
//强制类型转换,需使用instanceof关键字判断
if(animal instanceof Dog){
Dog dog5 = (Dog) animal;
}else{
System.out.println("无法完成强制类型转换");
}
此时运行程序,控制台没有任何输出,说明此强制类型可以成功转换