Java基础之面向对象的概念 继承---组合----枚举类
来源:互联网 发布:手机淘宝设置在哪里 编辑:程序博客网 时间:2024/06/07 06:50
Java基础之面向对象的概念 继承---组合----枚举类
本章作为面向对象概念的最后一篇,但是作为一名java程序员在面向对象的这条路上还很长。
一、继承与组合简介
继承是实现类重用的重要手段,但是继承的最大缺点是破坏了封装性,组合也是实现类重用的重要手段之一,这种方式则能提供更好的封装性。本章的上半部分将讲解继承和组合的区别和联系。
1.1使用继承应该注意的地方。
子类继承父类之后可以访问父类的变量和方法,因此严重破坏了父类的封装性,封装性是指:每个类都应该封装它内部的信息和实现细节,而只暴漏必要的方法给其他类使用。
子类访问父类的变量和方法的同时也造成了子类和父类的严重耦合。
为了解决这类的问题,我们应从父类的设计入手,有如下规则
1.尽量隐藏父类的内部数据,就是将父类的变量设置为private修饰。子类不能够直接访问。
2.不要让子类可以随意访问,修改父类的方法。可以使用访问修饰符(public protected private ),final修饰符进行方法的访问权限设定,来达到不同的访问需求。
3.尽量不要在父类中调用将被子类重写的方法,
4.如果将父类设计为不可继承的状态,则需要使用Final修饰,或者使用private修饰这个类的所有构造函数,则可以保证子类无法调用父类的构造函数,子类就无法继承该类。对于该类创建对象的问题,可以创建一个静态方法,返回该类的实例。
实例代码1:
package cn.com.basicFour;/** * @author fcs * 2014年8月28日 * 说明:子类重写的方法出现在父类的构造器中引发错误 */class Base{public Base(){test();}public void test(){System.out.println("我是父类中将被子类重写的方法。。。。");}}public class Sub extends Base { public static void main(String[] args) {Sub sub = new Sub();} private String name; //父类中的构造方法调用的是子类重写的方法,但是name的长度是一个null,运行报错。 public void test(){ System.out.println("我是子类重写的方法。。。。name的长度: "+name.length()); }}
那么什么时候需要继承呢?
说明:不仅需要保证子类是一种特殊的父类。而且需要下面两个条件之一
1.子类需要额外增加属性,而不仅仅是属性值的改变。
2.子类需要增加自己独有的行为方式,(包括增加新的方法或重写父类的方法)
上面说明了继承的注意事项,如果只是考虑到继承的复用性,那也可以使用组合实现。
组合仅需将对象引用置于新类中即可
实例代码2:简单的组合演示
package cn.com.basicFour;class Animal{private void best(){System.out.println("心脏跳动。。。");}public void breath(){best();System.out.println("戏一口气。。。。吐一口气。。。");}}class Bird{//将Animal类嵌入可以继承的子类中private Animal a;public Bird(Animal animal){this.a = animal;}//重新定义自己的方法public void breath(){//直接使用Animal提供的方法。a.breath();}public void fly(){System.out.println("我在天空飞翔。。。。。");}}class Wolf{//将Animal类嵌入可以继承的子类中private Animal a;public Wolf(Animal animal){this.a = animal;}//重新定义自己的方法public void breath(){//直接使用Animal提供的方法。a.breath();}public void run(){System.out.println("我在陆地上奔跑。。。。。");}}public class CompositeTest { public static void main(String[] args) {//此时需要显示的创建被嵌入的对象 Animal al = new Animal(); Bird bird = new Bird(al); bird.fly();bird.breath(); Wolf wolf = new Wolf(al); wolf.breath(); wolf.run();}}
结论:
继承是对已有的类进行改造,来达到某些特定的需求。
如果两个类之间有明确的整体和部分的关系,可以使用组合关系实现复用。
继承要表达的思想是一种“is-A”关系,组合要表达的思想是“has-A”关系。
一、枚举类
说明:在某些情况下,一个类的对象是有限而且固定的。在java里被称为枚举类。
1.1枚举类说明:
1. Java5 新增了一个enum关键字(与class ,interface地位相同),用以定义枚举类。
2.枚举类是一种特殊的类,可以有自己的属性,方法,可以实现一个或者多个接口,也可以定义自己的构造函数,
3.一个java源文件最多只能定义一个public 访问权限的枚举类,该源文件名必须和该枚举类名相同。
4.枚举类与普通类的区别
1.使用ENUM定义的枚举类默认继承了java.long.Enum类,
而不是继承Object类,java.long.Enum类实现了java.long.Serializable和java.long.Comparable接口。、
2.使用ENUM定义的非抽象的枚举类默认会使用Final修饰,因此枚举类不能派生子类。
3.枚举类的构造函数只能使用private访问修饰符。
4.枚举类的所有实例必须在枚举类的第一行显示列出,否则这个枚举类永远都不能产生实例,系统会自动为这些实例添加public static Final修饰。
1.2手动实现枚举类
设计方式
1.通过private将构造函数隐藏起来。
2.将这个类的所有可能的实例使用public static Final修饰。
3.可以提供一些静态方法,允许其他程序根据特定的参数来获取与之匹配的实例。
实例代码3:
package cn.com.basicFour;/** * * @author fcs * 2014年8月28日 * 说明:手动实现枚举类 * 该类是一个不可变类 */public class Season { private final String name; private final String desc; public Season(String name, String desc) {this.name = name;this.desc = desc;}public static final Season SPRING = new Season("春天","出游踏春");public static final Season SUMMER = new Season("夏天","夏日炎炎");public static final Season FALL = new Season("秋天","秋风飒飒");public static final Season WINTER = new Season("冬天","围炉赏雪");public String getName() {return name;}public String getDesc() {return desc;} //静态工厂方法实现返回season的实例public static Season getSeason(int seasonNum){switch(seasonNum){case 1:return SPRING;case 2:return SUMMER;case 3: return FALL;case 4:return WINTER;default: return null;}}}public class SeasonTest { public SeasonTest(Season season){ System.out.println(season.getName()+" 是一个"+season.getDesc()+"的季节。。。。"); } public static void main(String[] args) {//直接使用Season的FALL常量代表一个Season实例 new SeasonTest(Season.FALL); }}
说明:使用枚举类可以使程序更加健壮,避免创建对象的随意性。
可以使用这种方式:静态常量
Public static final int SEASON_SPRING = 1;
....
这种方式存在一些问题:
1.类型不安全,因为这些常量可以相加。
2.没有命名空间,容易与其他常量或者变量混淆。
3.打印输出的意义不明确。1指的是什么
实例代码4:
//枚举类演示
public enum Gender { MALE,FEMALE; private String name; //定义public修饰的变量 public void setName(String name){ switch(this){ case MALE: if(name.equals("男")){ this.name = name; }else{ System.out.println("参数错误。。。。。"); } break; case FEMALE: if(name.equals("女")){ this.name = name; }else{ System.out.println("参数错误。。。。。。"); } break; } } public String getName(){ return this.name; }}package cn.com.basicFour;public class GenderTest { public static void main(String[] args) {Gender g = Enum.valueOf(Gender.class, "FEMALE");g.setName("女");System.out.println(g+"代表 : "+g.getName());g.setName("男");System.out.println(g+"代表: "+g.getName());}}
说明:应该将上面的程序设计为不可变类。将所有的变量都使用final修饰符来修饰。
应该使用构造函数指定初始值,列出枚举值时就必须对应的传入参数。
实例代码5:
//枚举类与构造函数public enum Gender2 {//枚举类必须使用对应的构造函数实现 MALE("男"),FEMALE("女"); private final String name; private Gender2(String name){ this.name = name; } public String getName(){ return this.name; }}1.3实现接口的枚举类实例代码6:public enum Gender3 implements GenderDesc{//;//必须带上这个分号,当没有枚举类型时。MALE("男"){ //这种方式相当于一个匿名内部子类 public void info() {System.out.println("这个枚举值代表男性。。。。。"); }},FEMALE("女"){ public void info() {System.out.println("这个枚举值代表女性。。。。"); }};public void info() {System.out.println("这是用于定义性别的枚举类。。。。。");} private final String name; private Gender3(String name){ this.name = name; } public String getName(){ return this.name; }}
注意:非抽象的枚举类才是默认使用final修饰的,对于一个抽象的枚举类而言,只要包含了抽象方法就是抽象枚举类,系统默认使用abstract修饰,而不是final修饰。
编译后程序会生成三个class文件:Gender.class,Gender$1.class,Gender%2.class
1.3包含抽象方法的枚举类
package cn.com.basicFour;/** * * @author fcs * 2014年8月28日 * 说明:正常的枚举计算 */public enum Operation { PLUS,MINS,TIMES,DIVIDE; //为枚举类定义一个方法,用于实现不同的运算 double eval(double x,double y){ switch(this){ case PLUS: return x+y; case MINS: return x - y; case TIMES: return x * y; case DIVIDE: return x / y; default: return 0; } } public static void main(String[] args) {System.out.println(Operation.PLUS.eval(23,22.1));System.out.println(Operation.MINS.eval(2233,22.1));System.out.println(Operation.TIMES.eval(2,22.1));System.out.println(Operation.DIVIDE.eval(22,22.1));}}带抽象方法的枚举类package cn.com.basicFour;/** * @author fcs * 2014年8月28日 * 说明:带抽象类的枚举 * ,每个枚举值都必须实现该抽象类 */public enum Operation2 { PLUS{@Overridepublic double eval(double x, double y) {return x+y;} }, MINES{ @Overridepublic double eval(double x, double y) {return x - y;} }, TIMES{ @Overridepublic double eval(double x, double y) {return x * y;} }, DIVIDES{ @Overridepublic double eval(double x, double y) {return x / y;} }; public abstract double eval(double x,double y); public static void main(String[] args) { System.out.println(Operation.PLUS.eval(23,22.1)); System.out.println(Operation.MINS.eval(2233,22.1)); System.out.println(Operation.TIMES.eval(2,22.1)); System.out.println(Operation.DIVIDE.eval(22,22.1)); }}
说明:
枚举类里定义抽象方法时不能使用abstract关键字将枚举类定义成抽象类(因为系统自动回为它添加abstract关键字),但因为枚举类需要显示创建枚举值,而不是作为父类,所以定义每个枚举值时必须为抽象方法提供实现,否则将出现编译错误- Java基础之面向对象的概念 继承---组合----枚举类
- java基础之面向对象的继承
- 面向对象编程的几个关键概念继承、多态、组合
- java基础之面向对象-继承
- java基础之面向对象-继承
- 面向对象的概念 | 类与对象 | java基础
- 【java基础】--(2)面向对象特征之概念、封装、继承
- JAVA_基础之面向对象的概念
- Java面向对象继承与组合的问题
- 面向对象之继承和组合浅谈
- 面向对象之继承和组合浅谈
- 面向对象之继承和组合浅谈
- 面向对象之继承和组合浅谈
- 面向对象之继承和组合浅谈
- 面向对象之继承和组合浅谈
- 面向对象之继承和组合浅谈
- 面向对象之继承和组合浅谈
- 面向对象之继承和组合浅谈
- 08-0. 查找整数(10)
- 交叉编译和交叉调试环境搭建及使用
- 08-2. 求矩阵的局部极大值(15)
- 2014 百度研发工程师笔试题
- C#判断是否润年
- Java基础之面向对象的概念 继承---组合----枚举类
- 08-3. 组个最小数 (20)
- hdu 1331(dp)
- POJ-3045
- Unity3D 消息分发
- MH370事故见解
- Android Studio中手动导入Eclipse Project
- iOS SEL类型
- LeetCode-Binary Tree Level Order Traversal