首页 > 编程语言 > 详细

Java基础知识随意记录

时间:2019-05-06 13:09:17      阅读:130      评论:0      收藏:0      [点我收藏+]

 

多态:

首先明确一点我们在这里只考虑运行时多态,而不考虑编译时多态(方法重载)。因此下列多态默认都是指运行时多态。
多态是面向对象编程里面的概念,一个接口的多种不同的实现方式,即为多态。注意这里的接口,不应理解得太死板,比如在java里面,继承一个类和实现一个接口本质上都是一种继承行为,因此都应该理解为多态的体现。
在计算机的世界里,尤其是编程的世界里,多态体现在:只有在运行的时候才知道引用变量所指向的具体实例对象。且有三个必要的条件:
继承
 重写/实现
 父类引用指向子类对象
多态的概念来源于生活,生活中的很多现象都是多态的体现,例如打印机,打印功能可以打印黑白色也可以打印彩色。同一款汽车可以用2.0l排量也可以有1.0l的排量。
多态的技术带来的一个重要影响是:由于一个借口可能有多个实现,而每个实现之间的大小,规模,是不一样的。因此多态对内存的分配是有影响的,不同的实现会有不同的内存分配. 这一点与现实世界的多态例子相比就会非常有意思,第一,我们会发现软件里的多态是动态的多态,而现实世界里的多态大部分是一个预先设定好的多态体现,现实里的多态更多的类似于编译时多态,即方法重载,例如打印机的例子。
 
多态通常有两种实现方法:
  1. 子类继承父类(extends)
  2. 类实现接口(implements)
核心之处就在于对父类方法的改写或对接口方法的实现,以取得在运行时不同的执行效果。要使用多态,在声明对象时就应该遵循一条法则:声明的总是父类类型或接口类型,而创建的是实际类型.
以ArrayList为例子,要使用多态的特性,要按照如下方式定义
List list = new ArrayList();
此外,在定义方法参数时也通常总是应该优先使用父类类型或接口类型,例如:
public void test(List list);
这样声明最大的好处在于它的灵活性,假如某一天ArrayList无法满足要求,我们希望用LinkedList来代替它,那么只需要在对象创建的地方把new ArrayList()改为new LinkedList即可,其它代码一概不用改动。
---------------------------不定时增加------------------------

 反射 :

       定义如下:java程序在运行状态中,对于任意一个类,都能够在运行时知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

问题1:什么叫获取一个方法,什么叫获取一个属性?
        这是一个很好的问题,理解了这个问题之后也就不会觉得反射过于抽象了。java当中提供了专门的方法的抽象Method类和专门的属性的抽象Field类,以及专门的所有类的抽象Class类,并提供了一系列的方法,来帮助我们获取一个类的属性和方法。获取到的属性和方法,将以普通对象的方式存在。与我们自己写的类并无任何区别。下面是一个代码例子:
public class MethodClass {    
       public static void main(String[] args) throws Exception {       
           //1.获取Class对象       
           Class xxxClass = Class.forName("com.XXX.XXX");       
           //2.获取所有公有方法       
          Method[] methodArray = xxxClass .getMethods();       
          //3.获取字段       
          Field[] fieldArray = xxxClass .getFields();  
  }}
反射原理:
       Class类与java.lang.reflect库一起对反射的概念提供了技术支持。java.lang.reflect类库包含了Field类,Method类以及Constructor类。这些类用来表示未知类里对应的成员。Class类提供了获取getFields()、getMethods()和getConstructors()等方法,而这些方法的返回值类型就定义在java.lang.reflect当中。
如果不知道某个对象的确切类型(即list引用到底是ArrayList类型还是LinkedList类型),RTTI可以告诉你,但是有一个前提:这个类型在编译时必须已知,这样才能使用RTTI来识别它。
要想理解反射的原理,必须要结合类加载机。反射机制并没有什么神奇之处,当通过反射与一个未知类型的对象打交道时,JVM只是简单地检查这个对象,看它属于哪个特定的类,然后再通过拿到的某一个类的全限定名去找这个类的Class文件 。因此,那个类的.class对于JVM来说必须是可获取的,要么在本地机器上,要么从网络获取。所以对于RTTI和反射之间的真正区别只在于:
RTTI,编译器在编译时打开和检查.class文件
 反射,运行时打开和检查.class文件
对于反射机制而言.class文件在编译时是不可获取的,所以是在运行时获取和检查.class文件。
总结起来说就是,反射是通过Class类和java.lang.reflect类库一起支持而实现的,其中每一个Class类的对象都对应了一个类,这些信息在编译时期就已经被存在了.class文件里面了,Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass方法自动构造的。对于我们定义的每一个类,在虚拟机中都有一个应的Class对象。
那么在运行时期,无论是通过字面量还是forName方法获取Class对象,都是去根据这个类的全限定名(全限定名必须是唯一的,这也间接回答了为什么类名不能重复这个问题。)然后获取对应的Class对象
总结: java虚拟机帮我们生成了类的class对象,而通过类的全限定名,我们可以去获取这个类的字节码.class文件,然后再获取这个类对应的class对象,再通过class对象提供的方法结合类Method,Filed,Constructor,就能获取到这个类的所有相关信息. 获取到这些信息之后,就可以使用Constructor创建对象,用get和set方法读取和修改与Field对象相关的字段,用invoke方法调用与Method对象关联的方法。
 
反射机制非常重要,应用也非常之广泛。在使用反射时,我们的代码里面可以出现任何一个具体的构造器,字段信息,方法,但是却能动态的生成对象,调用他们的方法,这是一个非常通用的功能,由此带来的价值也是惊人的。反射比较出名的应用有:
1. Spring/Mybatis等框架,行内有一句这样的老话:反射机制是Java框架的基石。最经典的就是xml的配置模式。
2. JDBC 的数据库的连接
3. 动态生成对象,应用于工厂模式中. spring的bean容器也就是一个工厂
4. jdk动态代理
利用反射获取传入接口的实现类
5. 注解机制的实现
   利用反射可以获取每一个filed,Filed类提供了getDeclaredAnnotations方法以数组形式返回这个字段所有的注解....
6. 编辑器代码自动提示的实现
等等

 反射样例:

反射应用实例
下面的代码是使用反射获取方法的例子程序
model类
package com.dr.Reflection.getMethodByReflect;
public class Student {   
//**************成员方法***************//   
public void show1(String s) {       
System.out.println("调用了:公有的,String参数的show1(): s = " + s);  
  }    
protected void show2() {  
      System.out.println("调用了:受保护的,无参的show2()");   
}    
void show3()
{       
System.out.println("调用了:默认的,无参的show3()");   
}    
private String show4(int age)
{       
System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age);        return "abcd";  
}
}
测试类
package com.dr.Reflection.getMethodByReflect;import java.lang.reflect.Method;
public class MethodClass {    
public static void main(String[] args) throws Exception {     
   //1.获取Class对象      
  Class stuClass = Class.forName("com.dr.Reflection.getMethodByReflect.Student");      
  //2.获取所有公有方法     
   System.out.println("***************获取所有的”公有“方法*******************");       
   stuClass.getMethods();       
    Method[] methodArray = stuClass.getMethods();       
for(Method m : methodArray){          
  /* 注意,这里虽然student类自身只写了一个public方法,但是由于java所有的类都继承于object类,因此object类中所有的public方法也会被打印出来 */       
     System.out.println(m);      
  }       
System.out.println("***************获取所有的方法,包括私有的*******************");      
  methodArray = stuClass.getDeclaredMethods();       
  for(Method m : methodArray)
{
   //不包含父类的,仅仅是这个自身定义的方法           
   System.out.println(m);       
}     
   System.out.println("***************获取公有的show1()方法*******************");       
Method m = stuClass.getMethod("show1", String.class);
//根据方法名称,以及参数,获取方法对象       
System.out.println(m);       
//实例化一个Student对象      
  Object obj = stuClass.getConstructor().newInstance();    
    m.invoke(obj, "刘德华");        
    System.out.println("***************获取私有的show4()方法******************");   
     m = stuClass.getDeclaredMethod("show4", int.class);       
     System.out.println(m);      
    m.setAccessible(true);//解除私有限定     
    Object result = m.invoke(obj, 20);
//需要两个参数,一个是要调用的对象(获取有反射),一个是实参    
    System.out.println("返回值:" + result);     
}
}

 

 

 

Java基础知识随意记录

原文:https://www.cnblogs.com/sjqyao/p/10818905.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!