抽象类和抽象方法
对于一个父类来说,如果其某个方法在父类之中实现出来没有任何意义,必须根据子类情况来进行不同的实现。那么就可以将当前方法声明为抽象方法,包含抽象方法的类 称为抽象类。
下面就是一个抽象类,用abstract 修饰的类就是一个抽象类。
abstract class Animal1{
abstract public void cry();//抽象方法不做具体实现。
public void fun1(){//非抽象类
}
}
关于抽象类要注意的问题:
- 抽象类不能被实例化成一个对象。
- 抽象类中可以有抽象方法,也有可以非抽象方法。
- 类中只要有抽象方法则必须被定义为抽象类。
抽象类和普通类的区别:
- 抽象类的子类必须实现父类的抽象方法。
- 抽象类必须设置权限为public 或者 protect , 缺省默认为public,private修饰的类被子类继承,所以不能修饰抽象方法
- 抽象类不能实例化一个对象。
抽象类的子类必须实现父类的抽象方法。
class Dog1 extends Animal1{
@Override
public void cry() {
System.out.println("wangwang.....");
}
}
如果一个抽象类继承了一个抽象类,那么可以不实现基类的抽象方法。
//如果一个抽象类继承了一个抽象类,那么可以不实现基类的抽象方法。
abstract class Cat1 extends Animal1{
abstract public void cry();
}
如果一个类再次继承了这个抽象类,必须进行实现抽象方法。
//如果一个类再次继承了这个抽象类,必须进行实现抽象方法。
class LittleCat extends Cat1{
@Override
public void cry() {
System.out.println("littleCat....");
}
}
密封类和密封方法
类和方法 被final修饰之后,类不能被继承,方法不能被修改。
class Base4{
//密封方法.表明当前方法不能被再次修改。
public final void fun1(){
System.out.println("base.fun1");
}
public void fun2(){
System.out.println("base.fun2");
}
}
class Derive4 extends Base4{
/*public void fun1(){
System.out.println("Derive.fun1");
}*///报错
public void fun2(){
System.out.println("Derive.fun2");
}
}
密封类的优点:
密封类可以防止有意的派生。
接口
接口主要是对行为进行抽象。
默认数据成员为 public static final。
默认成员方法为 public abstract(成员方法不能有具体的实现)。
interface A{
int age = 10;
void fun1();
public static final int age = 10;
public abstract void fun1();
}
interface B{
int b = 100;
void fun2();
}
在上面的方法中对于成员变量写不写 public static final 都一样,它默认就是 public static final。
接口的实现
每个类可以实现多个接口。
接口不可以实现接口。
class C implements A,B{
@Override
public void fun1() {
System.out.println("A.fun1");
}
@Override
public void fun2() {
System.out.println("B.fun2");
}
}
接口的继承
接口和接口之间可以继承。
interface A{
public void fun1();
}
interface B{
public void fun2();
}
interface C extends A,B{//接口 C 继承接口 A 和 B.
public void fun3();
}
class X implements C{//类 X 实现接口 C 必须实现接口A、B、C 里面所有的方法。
@Override
public void fun1() {
// TODO Auto-generated method stub
}
@Override
public void fun2() {
// TODO Auto-generated method stub
}
@Override
public void fun3() {
// TODO Auto-generated method stub
}
}
接口和抽象类的区别
接口可以被实现多个(解决了 java 的单继承问题),抽象类只能被继承一个。
抽象类可以拥有非抽象方法,而接口内都是抽象方法。
接口的数据成员变量都是public static final
接口是对行为的一种抽象,抽象类本身是对类整体的抽象。
接口的应用
Cloneable
Cloneable 接口是对对象的克隆,可以通过调用 clone( )方法对对象进行克隆。
class Money implements Cloneable{
double money = 10.0;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Person implements Cloneable{
public String name;
Money m;
public Person(String name) {
this.name = name;
m = new Money();
}
//重写 Object 克隆方法
@Override
protected Object clone() throws CloneNotSupportedException {
//Person 的重写
Person p = (Person)super.clone();
p.m = (Money)this.m.clone();//对当前对象的引用进行克隆
return p;
}
}
public static void main(String[] args) throws Exception {
Person p1 = new Person("caocao");
Person p2 = (Person)p1.clone();
System.out.println("p1:"+p1.m.money);
System.out.println("p2:"+p2.m.money);
p1.m.money = 1000;
System.out.println("===========");
System.out.println("p1:"+p1.m.money);
System.out.println("p2:"+p2.m.money);
}
运行结果:
p1:10.0
p2:10.0
===========
p1:1000.0
p2:10.0
注意,在 People clone( )中如果不对当前引用的对象进行克隆,则改变 p1.m.money 的值,p2.m.money 的值也接着改变。
因为此时两个对象指的是同一个 m。入下图所示。
如果对当前 Money 这个对象的引用克隆后,则入下图。
注意
此接口在使用的时候,clone()方法和 Cloneable 接口必须同时使用,不可单独使用,如果单独使用就会报异常,因为JVM(Java虚拟机)需要一个接口当做标志位,来判别其是否可以被克隆。
Comparable 接口
class Person1 implements Comparable<Person1>{
private String name;
private int age;
private double score;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public Person1(String name,int age,double score) {
super();
this.name = name;
this.age = age;
this.score = score;
}
@Override
public String toString() {
return "Person1 [name=" + name + ", age=" + age + ", score=" + score + "]";
}
//待排序的数据
public int compareTo(Person1 o) {
return age - o.age;
}
}
public static void main(String[] args) {
Person1[] array = new Person1[3];
array[0] = new Person1("caocao",18,29.0);
array[1] = new Person1("aliubei",19,30.0);
array[2] = new Person1("erke",21,10.0);
}
运行结果:
[Person1 [name=caocao, age=18, score=29.0], Person1 [name=aliubei, age=19, score=30.0],
Person1[name=erke, age=21, score=10.0]]
Comparable 接口里面有一个 ComparaTo 方法,必须在子类实现它。
sort(Object[] a) 这是一个专门为了数组排序的方法。
Comparator 比较器
public static void main(String[] args) {
Person1[] array = new Person1[3];
array[0] = new Person1("caocao",18,29.0);
array[1] = new Person1("aliubei",19,30.0);
array[2] = new Person1("erke",21,10.0);
//对数组内的数据根据年龄排序
Arrays.sort(array,new Comparator<Person1>(){
//传入的时候有由用户自己选择,
@Override
public int compare(Person1 p1, Person1 p2) {
int age1 = p1.getAge();
int age2 = p2.getAge();
return age1 > age2 ? age1 : (age1 == age2) ? 0 : -1;
}
});
System.out.println(Arrays.toString(array));
}
运行结果:
[Person1 [name=caocao, age=18, score=29.0], Person1 [name=aliubei, age=19, score=30.0],
Person1[name=erke, age=21, score=10.0]]
Comparator 比较器是一个接口,我们必须重写实现里面的方法,使得它可以按照用户的需求来执行操作,比较灵活。
接口虽然不能创建一个对象,但是可以创建一个匿名内部类。
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, c);
}
这个方法是用 Comparator 比较器来对对象排序。