JavaSE——抽象类和接口

一、引言

1、父类中定义了相关子类的共同属性和方法(行为);

2、接口中定义了类的共同行为(包括非相关的类);

二、抽象类和抽象方法

1、抽象类不能用来创建对象,抽象类可以没有抽象方法,或者可以全部都是抽象方法,这些方法将在具体的子类中实现;

      抽象方法以 ";" 结尾,没有具体实现; 

      必须抽象类父类声明指向子类引用;

2、抽象类和抽象方法都是abstract来修饰的;

3、abstract只能修饰类和方法,不能用来修饰属性和构造方法;

4、有抽象方法的类必须声明为抽象类,反之,抽象类不一定有抽象方法;

5、子类必须重写父类的所有抽象方法,否则子类还是一个抽象类;

扫描二维码关注公众号,回复: 6441909 查看本文章

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
		 */
	}

}

猜你喜欢

转载自blog.csdn.net/dyz4001/article/details/81749882