接口的详解_接口 对象=new 实现类

接口是为了实现多态。

接口是为了实现多态。

接口是为了实现多态。

先讲一下接口回调。

interface People{
   void peopleList();
}
class Student implements People{
    public void peopleList(){
        System.out.println("I’m a student.")}
}
class Teacher implements People{
    public void peopleList(){
        System.out.println("I’m a teacher.");
    }	
}
public class Example{
    public static void main(String args[]){
    People a;             //声明接口变量
    a=new Student();      //实例化,接口变量中存放对象的引用
    a.peopleList();        //接口回调
    a=new Teacher();     //实例化,接口变量中存放对象的引用
    a.peopleList();       //接口回调
    }
}
结果:
I’m a student.
I’m a teacher.
 
例子参考:https://zhidao.baidu.com/question/1923748969384870227.html

refer

今天在公司里面写一个接口及其实现类的时候,
遇到一个现象引起了我的思考。
我做的一个后台管理里面的查询功能,
在controller层对接口的方法进行实现的时候,
我采用的是接口的引用对象来实现。
为什么不采用实现类创建引用对象来调用方法实现呢?

按照正常的逻辑,
接口里面只定义了方法名称。
主要的实现还是在继承接口的实现类里面,
而我看了别人的代码,
他们也大部分都是创建接口对象来实现,
重写的方法体是在实现类里面,接口对象为什么就可以使用。
例如:

List list = new ArrayList();
//List是接口,ArrayList是它的实现类

原因:这就是JAVA多态的特点。
父类引用指向子类对象,
父类(接口)的引用就能够直接调用子类(实现类)的方法。

为什么在实际的开发过程中不采用直接创建实现类对象来调用方法呢?
我在知乎上看到这一篇文章,觉得非常收益,
这么做的主要目的还是为了能够减少开发过程中代码的修改量。
快速理解java多态的含义

自己把这篇文章归纳总结如下:
定义一个animal抽象类, 里面有两个方法。
接下里定义两个类(cat和dog)去继承animal,
cat和dog分别重写了animal中的方法。

我们在调用dog里面的方法之后,
想修改为调用cat的方法。 ----
只需要将Animal animal=new Dog()改成Animal
animal=new Catl(), 只改变了一个对象。
接着继续调用animal.sing(),animal.run()。
实际的开发过程中要维护大量的代码量,
如果要换一个对象,改的代码更少。

refer
知乎 Java 中的接口有什么作用?
博客园 深入理解Java的接口和抽象类

//implA 为接口 ClassB为其实现类
implA A=new ClassB();//接口类型的引用变量A 去接收对象地址
or
ClassB A=new ClassB();//类类型的引用变量A 去接收对象地址
interface A { //接口A               
 //接口的方法声明必须是 public abstract ,即便不写默认也是
    public void fun();

}
public class B implements A {

    @Override
    public void fun() {
        //your coding
    }

}

如果我们要使用B类对象,调用B类方法,我们很容易就会习惯的写出

A demo=new B();

用接口类型的引用变量demo,
去接收实现类B实例化出来的对象地址(这里的=是传递的地址)。

为什么不是B demo=new B();

呢,这样也不会有问题啊?
(当然A demo=newA();
是不可能的,因为接口是不能用来实例化对象的,
但可以用来声明一个接口类型的引用变量)。

先把结论丢出来吧
应该优先使用接口而不是类来引用对象,但只有存在适当的接口类型时

public class InterfaceTest {

    public static void main(String[] args) {

        PetInterface p = new Cat();
        p.talk();
        p.batheSelf();//无法调用 ,报错The method batheSelf() is undefined for the type PetInterface
    }

}

interface PetInterface {                

    public void talk();

}

class Dog implements PetInterface {

    @Override
    public void talk() {
        System.out.println("Bark!");
    }

}

class Cat implements PetInterface {

    @Override
    public void talk() {
        System.out.println("Meow!");
    }

    public void batheSelf() {
        System.out.println("Cat bathing");
    }

}

我们看到,
方法batheSelf()仅仅存在实现类中时,
若我们仍然使用接口来引用对象时
PetInterface p = newCat(),
那些仅仅存在实现类中的方法,
是无法直接调用的即p.batheSelf()无法调用会报错。

所以这时使用Cat p = new Cat()即类来引用是更好的。

也就是说,
使用接口类去引用对象是有前提条件的
——即实现类中全是接口类的方法的实现,没有自己单独的方法。
当实现类存在自己的方法时,使用实现类来声明变量。

【转型问题】

 public static void main(String[] args) {

        PetInterface p = new Cat();//向上转型 Cat->PetInterface 
        p.talk();
        p.batheSelf();//无法调用 ,报错The method batheSelf() is undefined for the type PetInterface
    }

我们说直接p.batheSelf()会报错,
这是因为向上转型的过程中Cat->PetInterface ,
对PetInterface 接口造成的唯一效应就是函数的“遗失”而非”获得”
(即遗失了实现类自己独有的函数方法batheSelf()),
而Cat向上转型至PetInterface可能会窄化其功能,
但无论如何不会窄于PetInterface接口功能。
当然也存在向下转型,

//p.batheSelf();替换为下面形式
((Cat)p).batheSelf();//向下转型,可正常调用执行
  • 82
    点赞
  • 151
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
1. 值型与引用型 结构是值型:值型在堆栈上分配地址,所有的基型都是结构型,例如:int 对应System.int32 结构,string 对应 system.string 结构 ,通过使用结构可以创建更多的值是引用型:引用型在堆上分配地址 堆栈的执行效率要比堆的执行效率高,可是堆栈的资源有限,不适合处理大的逻辑复杂的对象。所以结构处理作为基型对待的小对象,而处理某个商业逻辑 因为结构是值型所以结构之间的赋值可以创建新的结构,而是引用型,之间的赋值只是复制引用 注: 1.虽然结构与型不一样,可是他们的基型都是对象(object),c#中所有型的基型都是object 2.虽然结构的初始化也使用了New 操作符可是结构对象依然分配在堆栈上而不是堆上,如果不使用“新建”(new),那么在初始化所有字段之前,字段将保持未赋值状态,且对象不可用 2.继承性 结构:不能从另外一个结构或者继承,本身也不能被继承,虽然结构没有明确的用sealed声明,可是结构是隐式的sealed . :完全可扩展的,除非显示的声明sealed 否则可以继承其他接口,自身也能被继承 注:虽然结构不能被继承 可是结构能够继承接口,方法和继承接口一样 例如:结构实现接口 interface IImage { void Paint(); } struct Picture : IImage { public void Paint() { // painting code goes here } private int x, y, z; // other struct members } 3.内部结构: 结构: 没有默认的构造函数,但是可以添加构造函数 没有析构函数 没有 abstract 和 sealed(因为不能继承) 不能有protected 修饰符 可以不使用new 初始化 在结构中初始化实例字段是错误的 : 有默认的构造函数 有析构函数 可以使用 abstract 和 sealed 有protected 修饰符 必须使用new 初始化
两个现实中的例子: 1、B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到你内脏的生理情况。这是如何做到的呢?B超是B型超声波,它可以透过肚皮通过向你体内发射B型超声波,当超声波遇到内脏壁的时候就会产生一定的“回音”反射,然后把“回音”进行处理就可以显示出内脏的情况了(我不是医生也不是声学专家,不知说得是否准确^_^)。 2、地球内部结构:地球的内部结构大体可以分为三层:地壳、地幔和地核。地壳是固体,地核是液体,地幔则是半液半固的结构(中学地理的内容,大家还记得吧?)。如何在地球表面不用深入地球内部就知道其内部的构造呢?对,向地球发射“地震波”,“地震波”分两种一种是“横波”,另一种是“纵波”。“横波”只能穿透固体,而“纵波”既可穿透固体又可以穿透液体。通过在地面对纵波和横波的反回情况,我们就可以大体断定地球内部的构造了。 大家注意到这两个例子的共同特点,就是从一个对象的外部去了解对象内部的构造,而且都是利用了波的反射功能。在.NET中的反射也可以实现对象的外部来了解对象(或程序集)内部结构的功能,哪怕你不知道这个对象(或程序集)是个什么东西,另外.NET中的反射还可以运态创建对象并执行它其中的方法。 反射是.NET中的重要机制,通过反射,可以在运行时获得程序或程序集中每一个型(包括、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个型了如指掌。另外我还可以直接创建对象,即使这个对象型在编译时还不知道。 反射的用途: (1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找型并创建型的实例。 (2)使用Module了解包含模块的程序集以及模块中的等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。 (3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。 (4)使用MethodInfo了解方法的名称、返回型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。 (5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。 (6)使用EventInfo了解事件的名称、事件处理程序数据型、自定义属性、声明型和反射型等,添加或移除事件处理程序。 (7)使用PropertyInfo了解属性的名称、数据型、声明型、反射型和只读或可写状态等,获取或设置属性值。 (8)使用ParameterInfo了解参数的名称、数据型、是输入参数还是输出参数,以及参数在方法签名中的位置等。 反射用到的命名空间: System.Reflection System.Type System.Reflection.Assembly 反射用到的主要: System.Type --通过这个可以访问任何给定数据型的信息。 System.Reflection.Assembly--它可以用于访问给定程序集的信息,或者把这个程序集加载到程序中。 System.Type: System.Type 对于反射起着核心的作用。但它是一个抽象的基,Type有与每种数据型对应的派生,我们使用这个派生对象的方法、字段、属性来查找有关该型的所有信息。 获取给定型的Type引用有3种常用方式: ●使用 C# typeof 运算符。 Type t = typeof(string); ●使用对象GetType()方法。 string s = "grayworm"; Type t = s.GetType(); ●还可以调用Type的静态方法GetType()。 Type t = Type.GetType("System.String"); 上面这三代码都是获取string型的Type,在取出string型的Type引用t后,我们就可以通过t来探测string型的结构了。 string n = "grayworm"; Type t = n.GetType(); foreach (MemberInfo mi in t.GetMembers()) { Console.WriteLine("{0}/t{1}",mi.MemberType,mi.Name); } Type的属性: Name 数据型名 FullName 数据型的完全限定名(包括命名空间名) Namespace 定义数据型的命名空间名 IsAbstract 指示该型是否是抽象型 IsArray 指示该型是否是数组 IsClass 指示该型是否是 IsEnum 指示该型是否是枚举 IsInterface 指示该型是否是接口 IsPublic 指示该型是否是公有的 IsSealed 指示该型是否是密封 IsValueType 指示该型是否是值型 Type的方法: GetConstructor(), GetConstructors():返回ConstructorInfo型,用于取得该的构造函数的信息 GetEvent(), GetEvents():返回EventInfo型,用于取得该的事件的信息 GetField(), GetFields():返回FieldInfo型,用于取得该的字段(成员变量)的信息 GetInterface(), GetInterfaces():返回InterfaceInfo型,用于取得该实现接口的信息 GetMember(), GetMembers():返回MemberInfo型,用于取得该的所有成员的信息 GetMethod(), GetMethods():返回MethodInfo型,用于取得该的方法的信息 GetProperty(), GetProperties():返回PropertyInfo型,用于取得该的属性的信息 可以调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用MethodInfo, PropertyInfo和其他的Invoke()方法。 查看中的构造方法: NewClassw nc = new NewClassw(); Type t = nc.GetType(); ConstructorInfo[] ci = t.GetConstructors(); //获取的所有构造函数 foreach (ConstructorInfo c in ci) //遍历每一个构造函数 { ParameterInfo[] ps = c.GetParameters(); //取出每个构造函数的所有参数 foreach (ParameterInfo pi in ps) //遍历并打印所该构造函数的所有参数 { Console.Write(pi.ParameterType.ToString()+" "+pi.Name+","); } Console.WriteLine(); }
Java中的Comparable接口定义了一个compareTo方法,用于比较对象之间的大小关系。实现Comparable接口可以使用Arrays.sort()和Collections.sort()进行排序。 实现Comparable接口需要重写compareTo方法,该方法返回一个整数值,表示当前对象与另一个对象的大小关系。如果当前对象小于另一个对象,则返回负整数;如果当前对象等于另一个对象,则返回0;如果当前对象大于另一个对象,则返回正整数。 以下是一个示例实现Comparable接口: ``` public class Person implements Comparable<Person> { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } @Override public int compareTo(Person o) { return this.age - o.getAge(); } } ``` 在上面的示例中,Person实现了Comparable接口,并重写了compareTo方法。该方法比较两个Person对象的年龄大小关系。 如果要对Person对象进行排序,可以使用Arrays.sort()或Collections.sort()方法。例如: ``` Person[] persons = new Person[] { new Person("Tom", 25), new Person("Jack", 18), new Person("Mary", 30) }; Arrays.sort(persons); for (Person person : persons) { System.out.println(person.getName() + " " + person.getAge()); } ``` 该示例中,使用Arrays.sort()对Person对象数组进行排序,按照年龄从小到大排序。最后输出排序后的结果。 需要注意的是,实现Comparable接口必须能够比较大小,否则可能会抛出ClassCastException异常。因此,在重写compareTo方法时,应该考虑到的属性是否可以比较大小。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值