[Java基础教程]第十一章-Java类和对象
继承是面向对象的三个特性之一,Java语言通过继承父类和实现接口两种方式实现继承。Java的继承有两个比较重要的特点:单继承结构,每个类只能有一个父类;所有的类继承java.lang .Object类。Object类中包含了多个默认实现的方法,其中常用的有3个,hashCode,equals,toString:
hashCode:返回对象的哈希码,我们前面学习的HashSet和HashMap容器在put和get时会调用这个方法,默认实现是返回对象在内存上的地址。
equals:对象比较,默认比较对象的地址,所以两个对象之间使用默认equals是不相等的。通常应用中会重写equals方法,使用对象的关键属性做为对象的比较,比如Person对象我们应该比较该对象的身份证号,如果身份证号码一致则是同一个人。Java规范要求:根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。所以我们在重写equals的时候同时也会重写hashCode方法。
toString:正是因为这个方法的存在,我们才能对所有的对象进行打印。默认的toString实现为:类全名(包括包结构)@hashCode,我们通常会重写该方法为输出所有属性值拼接的字符串。
备注:子类中重新实现父类的方法就是重写。
我们接着前面一章的打酱油继续看,其中有一个人物我们没有处理,小明的妈妈,会做菜的家庭主妇,所以我们需要定义一个类Materfamilias它具有Person的所有属性和方法,并且具有cook的方法,会cook的还可能会是厨师,所以我们可以把cook抽象成一个接口类Cookor,结构如下:
接口的定义使用Interface关键字,继承类和实现类分别为extends和implements,java是单继承和多实现的方式,也就是说类可以实现多个接口,代码如下:
public interface Cookor { public void cook(); } public class Materfamilias extends Person implements Cookor { /** * @param name */ public Materfamilias(String name) { super(name); } /* (non-Javadoc) * @see com.sunhaojie.learntest.eleventh.Cookor#cook() */ @Override public void cook() { System.out.println(this.getName() + "煮了一顿饭"); } }
接口中的方法不能带有”{}”的实现。
在前面几章中我们定义类的属性和方法前面会加一个单词修饰,比如private,public等,这些是对属性和方法访问权限的定义。这些修饰符共4个分别为,private,protected,default(没有修饰符),public。4种修饰符对应的访问权限如下表:
当前类 | 子类 | 同一个包类 | 其他类 | |
private | Y | N | N | N |
protected | Y | Y | N | N |
default | Y | 同包?Y:N | Y | N |
public | Y | Y | Y | Y |
当前类:当前类中的方法
子类:继承当前类的子类
同一个包类:在同一个package下的类
其他类:以上3中以外的类
类的类,有点拗口,面向对象的思想,一切都是对象,那么类的定义也是对象,也有类描述-Class类,类的属性,类的方法等都是有类定义,通过这种方式访问类和对象的方式叫做反射。我们通过反射生成对象,获取属性,调用方法,代码如下:
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { Class<Materfamilias> materfamiliasClass = (Class<Materfamilias>) Class .forName("com.sunhaojie.learntest.eleventh.Materfamilias"); // 初始化对象,并调用cook方法 Materfamilias mama = materfamiliasClass.newInstance(); mama.cook(); // 获取父类name属性,并打印结果值 Field field = materfamiliasClass.getSuperclass().getDeclaredField("name"); field.setAccessible(true); String mamaName = (String) field.get(mama); System.out.println("mama.getName():" + mama.getName() + "; field get name:" + mamaName); // 调用无参方法cook Method cookMethod = materfamiliasClass.getDeclaredMethod("cook"); cookMethod.invoke(mama); // 调用父类有参方法 Method setNameMethod = materfamiliasClass.getSuperclass().getDeclaredMethod("setName", String.class); setNameMethod.invoke(mama, "xiao ming mama"); System.out.println(mama.getName()); }
我们在上面的代码中实现了初始化对象(这里需要一个无参的构造方法),获取属性值,调用有参和无参的方法。反射这种方式应用程序开发使用比较少,但是一些框架经常使用,所以我们这里做一个简单了解。
我们在前面的测试中会直接运行main方法,main方法前面有一个关键字static,这个关键字可以在属性和方法前,表示类属性和类方法,也就是不用初始化对象就可以调用,显然这个语法和面向对象思想相悖,但是某些场景下也会用到。
和Interface比较类似,有一种类的方法也不用实习,抽象类abstract,因为java是单继承结构,所以我们尽量使用Interface接口尽量少使用abstract抽象类。
枚举enum,这种类在定义明确种类,状态时经常使用,比如酱油,可以分为瓶装,袋装和无包装3种,我们就可以定义一个枚举类实现这种方式,使用枚举的优势是运行效率高。酱油类别枚举:
public enum SoyType { BOTTLED("瓶装"), BAG("袋装"), NOWRAP("无包装"); public String name; /** * 如果不需要属性,就可以不用定义构造方法 * * @param name */ private SoyType(String name) { this.name = name; } }
小练习:
打印Materfamilias类的属性和方法名称,以及父类和接口的属性和方法。
课程中的代码:
package com.sunhaojie.learntest.eleventh; /** * @ClassName Cookor * @Description 烹饪功能接口 * * @author sunhaojie 3113751575@qq.com * @date 2016年2月11日 上午12:05:28 */ public interface Cookor { public void cook(); } package com.sunhaojie.learntest.eleventh; import java.util.HashSet; import java.util.Set; import com.sunhaojie.learntest.tenth.Soy; /** * @ClassName Person * @Description 人 * * @author sunhaojie 3113751575@qq.com * @date 2016年2月3日 下午1:38:30 */ public class Person { /** * 名字 */ private String name; /** * 酱油列表 */ private Set<Soy> soyList; /** * * @Title buy * @Description 买酱油 * @param soy * @return void * * @author sunhaojie 3113751575@qq.com * @date 2016年2月3日 下午4:59:31 */ public void buy(Soy soy) { if (soyList == null) { this.soyList = new HashSet<Soy>(); } this.soyList.add(soy); } /** * @param name */ public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Soy> getSoyList() { return soyList; } public void setSoyList(Set<Soy> soyList) { this.soyList = soyList; } } package com.sunhaojie.learntest.eleventh; /** * @ClassName Materfamilias * @Description 家庭主妇 * * @author sunhaojie 3113751575@qq.com * @date 2016年2月10日 下午11:04:16 */ public class Materfamilias extends Person implements Cookor { /** * 无参构造方法 */ public Materfamilias() { super("mama"); } /** * @param name */ public Materfamilias(String name) { super(name); } /* (non-Javadoc) * @see com.sunhaojie.learntest.eleventh.Cookor#cook() */ @Override public void cook() { System.out.println(this.getName() + "煮了一顿饭"); } } package com.sunhaojie.learntest.eleventh; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @ClassName ClassTest * @Description 反射测试类 * * @author sunhaojie 3113751575@qq.com * @date 2016年2月11日 下午10:31:58 */ public class ClassTest { /** * @Title main * @Description main方法 * @param args * @return void * * @author sunhaojie 3113751575@qq.com * @throws ClassNotFoundException * @throws IllegalAccessException * @throws InstantiationException * @throws SecurityException * @throws NoSuchFieldException * @throws NoSuchMethodException * @throws InvocationTargetException * @throws IllegalArgumentException * @date 2016年2月11日 下午10:31:58 */ @SuppressWarnings("unchecked") public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { Class<Materfamilias> materfamiliasClass = (Class<Materfamilias>) Class .forName("com.sunhaojie.learntest.eleventh.Materfamilias"); // 初始化对象,并调用cook方法 Materfamilias mama = materfamiliasClass.newInstance(); mama.cook(); // 获取父类name属性,并打印结果值 Field field = materfamiliasClass.getSuperclass().getDeclaredField("name"); field.setAccessible(true); String mamaName = (String) field.get(mama); System.out.println("mama.getName():" + mama.getName() + "; field get name:" + mamaName); // 调用无参方法cook Method cookMethod = materfamiliasClass.getDeclaredMethod("cook"); cookMethod.invoke(mama); // 调用父类有参方法 Method setNameMethod = materfamiliasClass.getSuperclass().getDeclaredMethod("setName", String.class); setNameMethod.invoke(mama, "xiao ming mama"); System.out.println(mama.getName()); } } package com.sunhaojie.learntest.eleventh; /** * @ClassName SoyType * @Description 酱油种类 * * @author sunhaojie 3113751575@qq.com * @date 2016年2月11日 下午11:21:00 */ public enum SoyType { BOTTLED("瓶装"), BAG("袋装"), NOWRAP("无包装"); public String name; /** * 如果不需要属性,就可以不用定义构造方法 * * @param name */ private SoyType(String name) { this.name = name; } }
建议继续学习:
- 面向对象的Shell脚本 (阅读:5155)
- 用星际争霸讲解面向对象的概念 (阅读:4151)
- 使用PHP创建一个面向对象的博客 (阅读:4067)
- PHP面向对象编程的三大特性 (阅读:3349)
- 面向对象设计模式的核心法则 (阅读:3171)
- PHP内核介绍及扩展开发指南―类和对象 (阅读:2978)
- 对象的消息模型 (阅读:2505)
- jQuery之jQuery方法总是返回jQuery对象 (阅读:2366)
- 我所偏爱的 C 语言面向对象编程范式 (阅读:2072)
- 细说JavaScript中对象的属性和方法 (阅读:2051)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:sunhaojie 来源: 孙豪杰的博客
- 标签: 类 Java基础教程 对象
- 发布时间:2016-03-15 23:33:40
- [54] IOS安全–浅谈关于IOS加固的几种方法
- [54] 如何拿下简短的域名
- [54] Go Reflect 性能
- [53] android 开发入门
- [53] Oracle MTS模式下 进程地址与会话信
- [50] 图书馆的世界纪录
- [48] 【社会化设计】自我(self)部分――欢迎区
- [48] 读书笔记-壹百度:百度十年千倍的29条法则
- [39] 程序员技术练级攻略
- [31] 视觉调整-设计师 vs. 逻辑