目录
抽象
在进行接口和泛型的学习前,首先应该知道一个概念叫做抽象
抽象是不具体定义如何实现,只有一个壳,其内容由用户自己定义的一个概念,比如Arm公司只生产内核的框架,授权给各大厂商,这些厂商在Arm给的框架(技术档案)以及给出的一些功能上,自定义功能,自行组建硬件,这样就实现了抽象
上一篇文章写到的类由属性和方法组成,其中属性是抽象的,其具体内容要实例化后才能完成具象,但是方法是具体的,在类的定义中就给出了具体方法的实现
这里就会遇到一种情况,这里我以KFC百事可乐的制造方法为例,有一个KFC类,其中有制造可乐的方法,但是如果有一天一家思路新奇的KFC打算进行改革,想要将可口可乐作为制造品,该怎么办呢,由于KFC类早已封装完成,不能对KFC类中的制造方法进行修改,此时可能想到的方法是新定义一个类继承KFC类,在这个子类中对制造方法进行重写,如下
public class KFC {
public void make_coke(){
System.out.println("pepsi");
}
}
public class KFC_new extends KFC {
public void make_coke(){
System.out.println("coke cola");
}
}
这样子每次有人想创新就得新定义一个子类,有没有一种办法能够不用定义一个新的子类,但是能够用自己的方式来写方法呢?接口(interface)应运而生!接口的作用就是告诉类,你要实现我这种接口代表的功能,你就必须实现某些方法,我才能承认你确实拥有该接口代表的某种能力
接口(interface)
定义格式
interface <interface_name>{...},如下定义一个接口Make_Coke
interface Make_Coke{ }
接口中的内容
1. 接口中可以定义抽象方法,也就是没有方法体的方法,默认为public static abstract
2. 接口中可以定义属性,但是是常量,必须赋值,默认为public static final
3. 接口中也可以定义非抽象方法,但是必须用default修饰
定义接口例子
interface Make_Coke{
//抽象方法
void make_coke();
//非抽象方法
default void mydefault(){
System.out.println("default");
}
}
接口具体化
一个接口可以被一个类实现,或者说具体化,但是这个类必须实现这个接口中的所有抽象方法,也可以重写其非抽象(default)方法,要实现这个接口,使用implements关键字
格式为:class <class_name> implements <interface_name>,在上例中可以具体化一个百事可乐类,一个可口可乐类,其中分别实现了不同的方法,一个制造百事可乐,一个制造可口可乐
class Make_Pepsi implements Make_Coke{
public void make_coke() {
System.out.println("make pepsi");
}
}
class Make_Cokecola implements Make_Coke{
public void make_coke() {
System.out.println("make cokecola");
}
}
这也是接口存在的意义,能够调用相同的上层方法,但是底层实现却不同,有利于封装
接口还有一个重要的地方,接口可以实现多继承,而类只能单继承,比如我又有一个制造果汁的类Make_Juice,可以用一个类来继承制造果汁的同时继承制造可乐,并在具体实现方面个性化地制造百事可乐和制造橙汁,多继承提供了只需要一个类就能实现多个接口的便利
interface Make_Coke{
void make_coke();
}
interface Make_Juice{
void make_juice();
}
class Make_Drink implements Make_Coke,Make_Juice{
public void make_coke() {
System.out.println("make pepsi");
}
public void make_juice() {
System.out.println("make orange juice");
}
}
使用具体化的接口
这里有一种简单的使用方法,直接声明Make_Cokecola类mcc,然后使用其中的方法
class test1{
public static void main(String[] args) {
Make_Cokecola mcc = new Make_Cokecola();
mcc.make_coke();
}
}
还可以联想并利用上一篇中向上转型的原理,声明一个Make_Coke类mc,但是创建的是继承了它的Make_Cokecola类,这里也体现了Java的多态特性!
class test1{
public static void main(String[] args) {
Make_Coke mc = new Make_Cokecola();
mc.make_coke();
}
}
如果想在KFC类中实现的话,只需要在KFC类中定义一个Make_Coke类KFC_mc,并封装一下make_coke函数,随后在实例中调用即可!
public class KFC {
Make_Coke KFC_mc;
public void make_coke(){
KFC_mc.make_coke();
}
}
class test1{
public static void main(String[] args) {
KFC kfc = new KFC();
kfc.KFC_mc = new Make_Cokecola();
kfc.make_coke();
}
}
如果KFC将其类写成这种形式,就给了连锁商家一些能够DIY彰显个性的东西!联想到生活中的例子USB,一台电脑有一个USB接口,可以连接许多设备,这些设备类型不同,比如手机、MP3、键盘等,这些都可以implements USB接口,然后在电脑上使用,但是各自的驱动文件会在各自对应的抽象方法实现中体现,这样就实现了USB接口的复用,这其实在生活中就是一个“标准”,而在Java中这个“标准”就是接口定义的!
泛型
在学习泛型前就有意无意间知道泛型在Java中的重要地位,Java中的泛型与C++中的模板其实有相通之处,都是为了实现通用设计
泛型的本质是参数化类型,即给类型指定一个参数,然后在编写代码时都是用这个参数,然后在具体使用时再具体此参数,那样这个类型就可以在使用时决定了,而非在编写代码时就定死,这样也就实现了设计的通用化
想象一个容器V,在设计时如果规定其可以容纳的内容类型是String,则在后续使用中就只能在其中放String,如果我用泛型的概念,在设计它时不规定它的内容类型,而是用泛型来规定,在后续使用时由用户来确定这个泛型到底是什么类型,是不是就实现了通用化?
定义格式
泛型可以用在类、接口和方法中,在一个目标后面加上<>,尖括号中用一个符号表示该泛型,可以自定义,这样就可以了,下面给了定义例子
public class myVector<T>{
private T v;
myVector(T value){
this.v = value;
}
public T get_v(){
return v;
}
};
具体化使用泛型
上面定义了一个带有泛型的myVector类,在使用时,只需要在创建一个myVector类时在泛型处加上用户所需要的类型即可
class test2{
public static void main(String[] args) {
myVector<Integer> v_int = new myVector<>(1);
myVector<String> v_string = new myVector<>("v_string");
System.out.println(v_int.get_v());
System.out.println(v_string.get_v());
}
};
这里需要注意以下几点:
1. 在具体化泛型时,在<>中的类型需要写全拼,并且第一个字母大写,比如int要写成Integer,char要写成Character,double要写成Double
2. new时<>中不带任何参数,空着就行
3. 使用泛型时,每处泛型都必须相同,否则编译错误!
上面提到的是泛型类,下面看看泛型接口和泛型方法
泛型接口
与泛型类一样,泛型也可以应用于接口,原理相同,这里直接给一个例子
interface Get<T>{
T get(T[] a,int i);
};
同样的,可以具体化这个接口
class Get_String implements Get<String>{
public String get(String[] s,int i){
System.out.println(s[i]);
return s[i];
}
};
class Get_Int implements Get<Integer>{
public Integer get(Integer[] a,int i){
return a[i];
}
};
根据自己的需求,可以实例化不同的Get子类
泛型接口与泛型类配合
泛型接口可以跟泛型类配合,实现更加强大的通用化,这里也直接给出上面例子的拓展
public class myVector<T>{
private T[] values;
Get<T> myvector_get;
myVector(T[] value){
this.values = value;
}
public T get(int i){
return myvector_get.get(values,i);
}
};
下面给出测试代码,可以正确get到第2个元素3
class test2{
public static void main(String[] args) {
Integer[] a = {1,2,3,4,5};
myVector<Integer> myV_int = new myVector<>(a);
myV_int.myvector_get = new Get_Int();
System.out.println(myV_int.get(2));
}
};
或者也可以不指定myV_int的泛型类型,直接空着,也能自动识别
myVector myV_int = new myVector<>(a);
泛型方法
泛型可以用于方法,实际上在上面两个例子中已经用到了,这里不做赘述,直接上例子
class test{
public <T> T generea(T t){
return t;
}
}
测试如下
class test2{
public static void main(String[] args) {
test tt = new test();
System.out.println(tt.generea("hello"));
}
};
泛型继承
public class Caculate<T extends String> {
private T num;
}