网站首页 > java教程 正文
继承是实现类重用的重要手段,但是继承带来了一个最大的坏处:破坏封装。相比之下,组合也是实现类重用的重要方式,而采用组合方式来实现类重用并能提供更好的封装。下面详细介绍继承和组合之间的联系与区别。
5.8.1 使用继承的注意点
子类扩展父类时,子类可以从父类继承得到Filed和方法。如果访问权限允许,子类可以直接访问父类的Field和方法,相当于子类可以直接复用父类的Field和方法。继承带来了高度复用的同时,也带来了一个严重的问题:那就是继承严重破坏了父类的封装性。封装:每个类都不可以随意访问其父类的Field和方法,父类只需要暴漏必要的方法给其他类使用。但是在继承关系中,子类可以直接访问父类的Field和方法,从而造成子类与父类的严重耦合。
父类的实现细节对于子类来说不再透明,子类可以访问父类的Field和方法,并可以改变父类的方法的实现细节,从而导致子类可以任意的篡改父类的方法和属性(Field)
举例1:
package com.langsin.test;
public class Bird {
public String name = "小鸟";
public void fly(){
System.out.println(this.name+"可以在天空中自由飞翔。。。");
}
Public void run(){
this.fly();
}
}
篡改属性:
package com.langsin.test;
public class Ostrich extends Bird {
public void test(){
this.name = "大象"; //任意篡改了父类的属性信息
this.fly();
}
public static void main(String[] args) {
Ostrich os = new Ostrich();
os.test();
}
}
篡改方法:
package com.langsin.test;
public class Ostrich extends Bird {
public void test(){
this.fly();
}
//任意篡改方法
public void fly(){
System.out.println(this.name+"在水中游来游去。。。");
}
public static void main(String[] args) {
Ostrich os = new Ostrich();
os.test();
}
}
对于此种问题,基于保证父类有良好的封装,不会被子类随意改变,设计父类时通常遵循如下规则:
1、 尽量隐藏父类的内部数据,尽量把父类的所有Field都设置成private访问类型,不让子类直接访问父类的Field.
2、 不要让子类可以随意访问、修改父类的方法。父类中作为辅助其他方法的工具方法,应该使用private访问控制符修饰,让子类无法访问该方法。如果父类中的方法需要被外部类调用,则必须以public修饰,但又不希望被子类重写该方法,可以使用final修饰符来修饰,表示最终的方法。如果父类的方法可以让子类重写,但是又不希望被其他类自由访问,可以使用protected来修饰该方法。
3、 不要在父类构造方法中调用将会被子类重写的方法。因为如果方法被子类重写,那么子类在实例化时,会调用父类的构造方法来进行父类初始化时,构造方法中调用的是被子类重写的方法,而不是本身的那个方法。
举例2:
package com.langsin.test;
public class Bird {
Bird(){
this.fly();
}
public void fly(){
System.out.println("小鸟可以在天空中自由飞翔。。。");
}
}
package com.langsin.test;
publicclass Ostrich extends Bird {
public void fly(){
System.out.println("鱼儿在水中游来游去。。。");
}
public static void main(String[] args) {
Ostrich os = new Ostrich(); //在创建子类对象时,父类构造方法调用了被子类重写的方法。
}
}
注意:如果把某些类设置成最终类,即使用final修饰符修饰这个类,那么这个类将不能被当成父类。例如JDK所提供的java.lang.String类,java.lang.System类,都是最终类。
5.8.2 利用组合实现复用
如果需要复用一个类,除了把这个类当成父类来继承之外,还可以把该类当成另外一个类的组成部分,从而允许新类直接复用该类的public方法。因此,不管是继承还是组合,都允许在新类中直接复用旧类的方法。
举例1:
package com.langsin.basic;
//商品类
public class Product {
// 成员变量都是私有的。如果用到多个类中有成员变量是重复的,尽量把成员变量和方法分别开来。
private String p_name;
private String p_price;
private String p_num;
public Product(){}
public Product(String p_name, String p_price, String p_num) {
this.p_name = p_name;
this.p_price = p_price;
this.p_num = p_num;
}
public String getP_name() {
return p_name;
}
public void setP_name(String p_name) {
this.p_name = p_name;
}
public String getP_price() {
return p_price;
}
public void setP_price(String p_price) {
this.p_price = p_price;
}
public String getP_num() {
return p_num;
}
public void setP_num(String p_num) {
this.p_num = p_num;
}
}
package com.langsin.basic;
//订单类
public class Order {
private String orderName;
private String date;
private String orderId;
private double money;
private Product[] prods = null;
Order(String orderName,String date,String orderId){
this.orderId = orderId;
this.date = date;
this.orderName = orderName;
}
public Product[] getProds() {
return prods;
}
public void setProds(Product[] prods) {
this.prods = prods;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
public static void main(String[] args) {
Product[] prods = new Product[3];
Product p1 = new Product("笔记本","1200","1");
Product p2 = new Product("电视机","2000","1");
Product p3 = new Product("冰箱","1500","1");
prods[0] = p1;
prods[1] = p2;
prods[2] = p3;
//商品购买完成
Order order = new Order("张三","20151212","CD001");
order.setProds(prods);
//查看此订单的详细信息
System.out.println("订单用户:"+order.orderName +" 订单日期:"+order.date);
System.out.println("此订单的详细商品如下:==================");
for(int i=0;i<order.getProds().length;i++){
Product prod = order.getProds()[i];//
System.out.println("商品名称:"+prod.getP_name()+" 商品价格:"+prod.getP_price()+" 购买数量:"+prod.getP_num());
}
}
}
- 上一篇: Java中的多态(java中的多态怎么理解)
- 下一篇: Java的多态(java的多态的实现)
猜你喜欢
- 2024-09-27 Java多态重载和重写(类方法设计中多态与重载的区别是什么)
- 2024-09-27 什么是多态?Java为什么要用多态?(java中什么是多态性)
- 2024-09-27 别找了!月薪30k的T6大佬整理的Java多态知识点总结,限时收藏
- 2024-09-27 三十一、Java面向对象编程特性-多态
- 2024-09-27 Java多中包括态理解、多态实现、重写、转型和抽象类
- 2024-09-27 Java中的封装、继承和多态,你真的都懂了吗
- 2024-09-27 java基础之多态与向上转型,很用心的一篇笔记
- 2024-09-27 Java多态的介绍-学习日志(java的多态是什么)
- 2024-09-27 Java路径-25-Java多态(java路径错误)
- 2024-09-27 Java中的多态(基础语法)(java多态的定义和应用)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)