[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脚本 (阅读:5697)
- 使用PHP创建一个面向对象的博客 (阅读:4868)
- 用星际争霸讲解面向对象的概念 (阅读:4799)
- PHP面向对象编程的三大特性 (阅读:4209)
- 面向对象设计模式的核心法则 (阅读:3955)
- PHP内核介绍及扩展开发指南―类和对象 (阅读:3705)
- 对象的消息模型 (阅读:3208)
- [Java基础教程]第十三章-Java多线程 (阅读:3025)
- jQuery之jQuery方法总是返回jQuery对象 (阅读:3010)
- [Java基础教程]第十二章-Java输入输出流 (阅读:2972)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:sunhaojie 来源: 孙豪杰的博客
- 标签: 类 Java基础教程 对象
- 发布时间:2016-03-15 23:33:40
-
[939] WordPress插件开发 -- 在插件使用 -
[117] 解决 nginx 反向代理网页首尾出现神秘字 -
[50] 如何保证一个程序在单台服务器上只有唯一实例( -
[48] 整理了一份招PHP高级工程师的面试题 -
[48] 用 Jquery 模拟 select -
[48] 海量小文件存储 -
[47] ps 命令常见用法 -
[47] Innodb分表太多或者表分区太多,会导致内 -
[46] 全站换域名时利用nginx和javascri -
[45] find命令的一点注意事项

