一、引言
1、父类中定义了相关子类的共同属性和方法(行为);
2、接口中定义了类的共同行为(包括非相关的类);
二、抽象类和抽象方法
1、抽象类不能用来创建对象,抽象类可以没有抽象方法,或者可以全部都是抽象方法,这些方法将在具体的子类中实现;
抽象方法以 ";" 结尾,没有具体实现;
必须抽象类父类声明指向子类引用;
2、抽象类和抽象方法都是abstract来修饰的;
3、abstract只能修饰类和方法,不能用来修饰属性和构造方法;
4、有抽象方法的类必须声明为抽象类,反之,抽象类不一定有抽象方法;
5、子类必须重写父类的所有抽象方法,否则子类还是一个抽象类;
6、abstract不能和private,static共同修饰方法;
abstract不能喝final公用修饰一个方法和类;
也就是说,所有的抽象方法都是非私有,非静态,可继承的,所有的抽象类也是可继承的;
7、在继承结构中,每个新子类都使类变得越来越明确和具体;
如果从子类向上往父类追溯,类就会变得更加的通用、不明确;
在设计一个类的时候,应该确保父类包含它的子类的共同特征;
8、抽象类的构造方法建议定义为protected类型,因为只被它的子类访问,在创建一个具体的子类对象时,它的父类构造方法被调用以初始化父类中定义的数据域;
9、子类可以覆盖父类的方法,并将它定义为abstract,父类方法实现在子类中无效是可以这么做,这种情况子类必须定义为抽象类;
10、父类是具体的,子类也可以是抽象的;
三、Number抽象类
1、Numbei类是数值包装类以及BigInteger和BigDecimal的抽象父类;
四、GregorianCalendar和Calendar
1、java.util.Calendar是一个抽象的基类,可以提取出详细的日历信息;
2、Calendar类可以实现特定的日历系统,java支持公历(GregorainCalendar),农历和犹太历;
import java.util.*;
public class Test {
public static void main(String[] args) {
//创建Calendar对象
Calendar calendar = new GregorianCalendar();
System.out.println("当前时间是:"+new Date());
System.out.println("当前的年份:"+calendar.get(calendar.YEAR));
System.out.println("当前月份是:"+(calendar.get(calendar.MONTH)+1));
System.out.println("是当月的哪天:"+calendar.get(calendar.DATE));
System.out.println("是当月的哪天:"+calendar.get(calendar.DAY_OF_MONTH));
System.out.println("现在几点(24小时制):"+calendar.get(calendar.HOUR_OF_DAY));
System.out.println("现在几点(12小时制):"+calendar.get(calendar.HOUR));
System.out.println("现在的分钟数:"+calendar.get(calendar.MINUTE));
System.out.println("现在的秒数:"+calendar.get(calendar.SECOND));
System.out.println("现在星期几:"+calendar.get(calendar.DAY_OF_WEEK));
System.out.println("一年之中的哪天:"+calendar.get(calendar.DAY_OF_YEAR));
System.out.println("当月第几个星期:"+calendar.get(calendar.WEEK_OF_MONTH));
System.out.println("当年第几个星期:"+calendar.get(calendar.WEEK_OF_YEAR));
System.out.println("上午还是下午:"+calendar.get(calendar.AM_PM));
}
}
3、Calendar的一些其他方法
import java.util.*;
public class Test {
public static void main(String[] args) {
//创建Calendar对象
Calendar calendar = new GregorianCalendar();
//位calendar设置一个用Date对象表示的时间
Date date = new Date();
calendar.setTime(date);
System.out.println(calendar.getTime());
//将当前天数设置完当月第六天
calendar.set(calendar.DAY_OF_MONTH, 6);
System.out.println(calendar.get(calendar.DAY_OF_MONTH));
//从当前天数减去五天
calendar.add(calendar.DAY_OF_MONTH, -5);
System.out.println(calendar.get(calendar.DAY_OF_MONTH));
//当年共有多少天,还可以统计当年共有多少周,当月共有多少周等等
System.out.println(calendar.getActualMaximum(calendar.DAY_OF_YEAR));
}
}
五、接口
1、接口是一种与类相似的结构,只包含常量和抽象方法;
2、接口的目的是指明相关或者不相关类的对象的共同行为;
3、接口的语法:
public interface Serializable extends 父接口1,父接口2...{
//接口中的抽象方法
}
public class 类名 extends 父类名 implements 接口1,接口2...{
//类中的方法
}
4、为什么说接口的感觉和抽象类很像呢?
在java中接口被看做一种特殊的类,就像常规类一样,每个接口在编译之后,都会形成独立的字节码文件;
5、和抽象类一样,可以使用接口作为引用变量的数据类型或类型转换的结果等;
6、接口的命名规则与类相同,如果修饰符是public,那么接口在整个项目中可见,如省略修饰符,该接口只在当前包可见;
7、接口中只能定义常量,不能定义变量,接口中的所有属性都会自动用public static final修饰,即接口中的所有属性都是全局静态常量,必须在定义时指定初始值,所以可以在写代码时省略它;
8、接口中的方法都是抽象方法,接口中的方法都会自动用public abstract修饰,即接口中只有全局抽象方法;
9、和抽象类一样,接口也不能实例化,接口中不能有构造方法;
10、接口之间可以通过extends实现继承关系,一个接口可以继承多个接口,但接口不能继承类;
11、接口的实现类必须实现接口的全部抽象方法,否则必须定义为抽象类;
12、如何使用接口
父类实现接口,之后再让子类继承父类,之后再把父类和接口中未实现的方法实现;
13、instanceof操作符
可以使用instanceof操作符来判断某个类是否实现了某个接口,或者某个对象是否属于某个类;
六、Comparable接口
1、Comparable接口是一个泛型接口,定义了compareTo方法,该方法判断this对象相对于给定对象o的顺序,并且当这个对象小于、等于或大于对象o时,分别返回负整数、0或正整数;
2、关于实现Comparable接口,重写compareTo方法的例子请看JavaSE——集合框架中的例子;
3、其他类型的数据排序比较简单,Arrays.sort方法是无法对汉字进行排序的,如对汉字字符串数组排序,需要执行区分语言环境的操作:
Comparator<Object> cmp = Collator.getInstance(java.util.Locale.CHINA);
String[] a= {"赵","钱","孙","李"};
Arrays.sort(a,cmp);
for (String string : a) {
System.out.println(string);
}
//输出:李钱孙赵
这种方式的缺点是:如果含有生僻汉字,那么排序结果会出现错误,所以推荐以下写法:
Comparator<Object> cmp = com.ibm.icu.text.Collator.getInstance(com.ibm.icu.util.ULocale.SIMPLIFIED_CHINESE);
String[] a= {"赵","钱","孙","李","钛"};
Arrays.sort(a,cmp);
for (String string : a) {
System.out.print(string);
}
//输出:李钱孙钛赵
此处需要配置一个jar包,或者可以百度搜pinyin4j,不再赘述;
七、Cloneable接口
1、Cloneable接口给出了一个可克隆的对象;
2、Cloneable接口中不包括任何常量和抽象方法,像这样的接口称为标记接口,用来表示一个类拥有某些特定的属性,例如:
public class Demo implements Cloneable{
}
上述例子将Demo类标记为可克隆的,它的对象可以使用在Object类中定义的clone( )方法;
3、克隆之后的对象是与原对象内容相同,但引用不同的一个新的对象;
4、Object类中的clone方法
protected native Object clone() throws CloneNotSupportedException;
这是Object类中的clone方法,从方法定义可知:
(1)、clone方法是native方法,native方法的效率远高于非native方法,因此用clone方法去做对象的拷贝,而不是 new 的copy方法;
(2)、此方法被protected修饰,这就表明如果想要在其他类中也能使用该方法,就必须继承(默认继承)并且重写它,将访问修饰符更改为public;
(3)、返回值是一个Object对象,所以要强制转换才可以;
5、clone方法的使用
package Cloneable接口;
class Demo {
private String name;
public Demo() {
name = "张三";
System.out.println("执行构造方法Demo");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class CloneableTest implements Cloneable {
private int id;
private Demo demo;
public CloneableTest(int id, Demo demo) {
this.id = id;
this.demo = demo;
System.out.println("执行构造方法CloneableTest");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Demo getDemo() {
return demo;
}
public void setDemo(Demo demo) {
this.demo = demo;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public static void main(String[] args) {
try {
Demo d = new Demo();
CloneableTest c1 = new CloneableTest(1, d);
CloneableTest c2 = (CloneableTest) c1.clone();
System.out.println("c1和c2的引用相同吗?" + (c1 == c2));
System.out.println("c1和c2的类类型相同吗?" + (c1.getClass() == c2.getClass()));
System.out.println("c1和c2的id相同吗?" + (c1.getId() == c2.getId()));
System.out.println("c1和c2的demo的引用相同吗?" + (c1.getDemo() == c2.getDemo()));
System.out.println("c1和c2的demo中的name的引用相同吗?" + (c1.getDemo().getName() == c2.getDemo().getName()));
/**
* 结果:
* 执行构造方法Demo
* 执行构造方法CloneableTest
* c1和c2的引用相同吗?false
* c1和c2的类类型相同吗?true
* c1和c2的id相同吗?true
* c1和c2的demo的引用相同吗?true
* c1和c2的demo中的name的引用相同吗?true
*/
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
(1)、如果想要使用该方法,除了继承Object类之外,还必须实现Cloneable接口:
(2)、clone是不走构造方法的;
(3)、克隆的对象和原对象是两个不同的对象,其地址指向两个不同的堆地址空间;
(4)、两个对象的getClass是相同的;
(5)、对于基本数据类型,clone的时候是按值传递,对于引用数据类型,clone的时候是复制引用;
综上得出结论:利用Object中的clone方法实现的只是浅克隆(shallow clone);
6、深克隆(deep clone)
1、先将对象序列化,之后再反序列化读取,代码如下:
package Cloneable接口;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Demo implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
public Demo() {
name = "张三";
System.out.println("执行构造方法Demo");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class CloneableTest implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int id;
private Demo demo;
public CloneableTest(int id, Demo demo) {
this.id = id;
this.demo = demo;
System.out.println("执行构造方法CloneableTest");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Demo getDemo() {
return demo;
}
public void setDemo(Demo demo) {
this.demo = demo;
}
//深克隆方法
public Object deepClone(){
ObjectOutputStream oos=null;
ObjectInputStream ois=null;
Object readObject=null;
try {
oos=new ObjectOutputStream(new FileOutputStream("E:/深克隆/deepClone.txt"));
oos.writeObject(this);
ois=new ObjectInputStream(new FileInputStream("E:/深克隆/deepClone.txt"));
readObject = ois.readObject();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
try {
if(ois!=null) {
ois.close();
}
if(oos!=null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return readObject;
}
public static void main(String[] args) {
Demo d = new Demo();
CloneableTest c1 = new CloneableTest(1, d);
CloneableTest c2 = (CloneableTest) c1.deepClone();
System.out.println("c1和c2的引用相同吗?" + (c1 == c2));
System.out.println("c1和c2的类类型相同吗?" + (c1.getClass() == c2.getClass()));
System.out.println("c1和c2的id相同吗?" + (c1.getId() == c2.getId()));
System.out.println("c1和c2的demo的引用相同吗?" + (c1.getDemo() == c2.getDemo()));
System.out.println("c1和c2的demo中的name的引用相同吗?" + (c1.getDemo().getName() == c2.getDemo().getName()));
/**
* 结果:
* 执行构造方法Demo
* 执行构造方法CloneableTest
* c1和c2的引用相同吗?false
* c1和c2的类类型相同吗?true
* c1和c2的id相同吗?true
* c1和c2的demo的引用相同吗?false
* c1和c2的demo中的name的引用相同吗?false
*/
}
}
2、调用clone方法先克隆出一个新对象,之后手动给新对象的各项数据域设置值,代码如下:
package Cloneable接口;
class Demo implements Cloneable{
private String name;
public Demo() {
name = "张三";
System.out.println("执行构造方法Demo");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class CloneableTest implements Cloneable{
private int id;
private Demo demo;
public CloneableTest(int id, Demo demo) {
this.id = id;
this.demo = demo;
System.out.println("执行构造方法CloneableTest");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Demo getDemo() {
return demo;
}
public void setDemo(Demo demo) {
this.demo = demo;
}
//手动实现深克隆
@Override
public Object clone() throws CloneNotSupportedException {
CloneableTest clone = (CloneableTest) super.clone();
clone.id=clone.getId();
clone.demo=(Demo) demo.clone();
String str=new String(clone.demo.getName());
clone.demo.setName(str);
return clone;
}
public static void main(String[] args) {
try {
Demo d = new Demo();
CloneableTest c1 = new CloneableTest(1, d);
CloneableTest c2 = (CloneableTest) c1.clone();
System.out.println("c1和c2的引用相同吗?" + (c1 == c2));
System.out.println("c1和c2的类类型相同吗?" + (c1.getClass() == c2.getClass()));
System.out.println("c1和c2的id相同吗?" + (c1.getId() == c2.getId()));
System.out.println("c1和c2的demo的引用相同吗?" + (c1.getDemo() == c2.getDemo()));
System.out.println("c1和c2的demo中的name的引用相同吗?" + (c1.getDemo().getName() == c2.getDemo().getName()));
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
/**
* 结果:
* 执行构造方法Demo
* 执行构造方法CloneableTest
* c1和c2的引用相同吗?false
* c1和c2的类类型相同吗?true
* c1和c2的id相同吗?true
* c1和c2的demo的引用相同吗?false
* c1和c2的demo中的name的引用相同吗?false
*/
}
}