• 基础语言知识JAVA


    1. 总结:

    JAVA比较重要的博客:

    http://www.runoob.com/java/java-tutorial.html     (JAVA教程)

    http://blog.csdn.net/jackfrued/article/details/44921941   (笔试题很好)

    http://www.runoob.com/java/java-examples.html    (练习题,很好)

    相关博客:

    JAVA总结

    Java提高篇

    Java面试题全集(上)

    总结下载:

    java基础知识总结

    java类:

    所有异常的父类 java.lang.Exception
       
       
       
       

    所有关键字:

    类别关键字说明
    访问控制 private 私有的
    protected 受保护的
    public 公共的
    类、方法和变量修饰符 abstract 声明抽象
    class
    extends 扩允,继承
    final 最终值,不可改变的
    implements 实现(接口)
    interface 接口
    native 本地,原生方法(非Java实现)
    new 新,创建
    static 静态
    strictfp 严格,精准
    synchronized 线程,同步
    transient 短暂
    volatile 易失
    程序控制语句 break 跳出循环
    case 定义一个值以供switch选择
    continue 继续
    default 默认
    do 运行
    else 否则
    for 循环
    if 如果
    instanceof 实例
    return 返回
    switch 根据值选择执行
    while 循环
    错误处理 assert 断言表达式是否为真
    catch 捕捉异常
    finally 有没有异常都执行
    throw 抛出一个异常对象
    throws 声明一个异常可能被抛出
    try 捕获异常
    包相关 import 引入
    package
    基本类型 boolean 布尔型
    byte 字节型
    char 字符型
    double 双精度浮点
    float 单精度浮点
    int 整型
    long 长整型
    short 短整型
    null
    变量引用 super 父类,超类
    this 本类
    void 无返回值
    保留关键字 goto 是关键字,但不能使用
    const 是关键字,但不能使用

    数据类型:

    - 原始类型:boolean,     char,      byte,short,   int(默认),    long(默认), float,double 
    - 包装类型:Boolean,Character,  Byte,Short,    Integer,              Long,        Float,Double

    1、float f=3.4;是否正确? 
    答:不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;。

    2、short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗? 
    答:对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给short型。而short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 = (short)(s1 + 1);其中有隐含的强制类型转换。

    形参实参:

    名词解析:

    1.形参:用来接收调用该方法时传递的参数。只有在被调用的时候才分配内存空间,一旦调用结束,就释放内存空间。因此仅仅在方法内有效。

    2.实参:传递给被调用方法的值,预先创建并赋予确定值。

    3.传值调用:传值调用中传递的参数为基本数据类型,参数视为形参。

    4.传引用调用:传引用调用中,如果传递的参数是引用数据类型,参数视为实参。在调用的过程中,将实参的地址传递给了形参,形参上的改变都发生在实参上。

    案例分析:

    1.基础数据类型(传值调用)

    传值,方法不会改变实参的值。

     

    2.引用数据类型(引用调用)
    传引用,方法体内改变形参引用,不会改变实参的引用,但有可能改变实参对象的属性值。

    举两个例子:

    (1)方法体内改变形参引用,但不会改变实参引用 ,实参值不变。

    public class TestFun2 {  
        public static void testStr(String str){  
            str="hello";//型参指向字符串 “hello”  
        }  
        public static void main(String[] args) {  
            String s="1" ;  
            TestFun2.testStr(s);  
            System.out.println("s="+s); //实参s引用没变,值也不变  
        }  
    } 
    执行结果打印:s=1
     
    (2)方法体内,通过引用改变了实际参数对象的内容,注意是“内容”,引用还是不变的。
    public class TestFun4 {  
        public static void testStringBuffer(StringBuffer sb){  
            sb.append("java");//改变了实参的内容  
        }  
        public static void main(String[] args) {  
            StringBuffer sb= new StringBuffer("my ");  
            new TestFun4().testStringBuffer(sb);  
            System.out.println("sb="+sb.toString());//内容变化了  
        }  
    }  

    执行结果,打印:sb=my java 。

      所以比较参数是String和StringBuffer 的两个例子就会理解什么是“改变实参对象内容”了。

    总结:

    1.java的基本数据类型是传值调用,对象引用类型是传引用。

    2.当传值调用时,改变的是形参的值,并没有改变实参的值,实参的值可以传递给形参,但是,这个传递是单向的,形参不能传递回实参。

    3.当引用调用时,如果参数是对象,无论对对象做了何种操作,都不会改变实参对象的引用,但是如果改变了对象的内容,就会改变实参对象的内容。

    上诉的String和StringBuffer:简单地说,就是一个变量和常量的关系。StringBuffer对象的内容可以修改;而String对象一旦产生后就不可以被修改,重新赋值其实是两个对象。

    http://blog.csdn.net/lclai/article/details/6141548

    instanceof

    子类是父类的类型,但父类不是子类的类型。

    子类的实例可以声明为父类型,但父类的实例不能声明为子类型。

    class Vehicle {}
     
    public class Car extends Vehicle {
        public static void main(String args[]){
            Vehicle v1 = new Vehicle(); //父类型
            Vehicle v2 = new Car(); //子类的实例可以声明为父类型
            Car c1 = new Car();    // 子类型
            Car c2 = new Vehicle(); //这句会报错,父类型的实例不能声明为子类型
     
            //Car(子类)是Vehicle(父类)类型, Vehicle(父类)不是Car(子类)类型
            boolean result1 =  c1 instanceof Vehicle;    // true
            boolean result2 =  c1 instanceof Car;        // true
            boolean result3 =  v1 instanceof Vehicle;    // true
            boolean result4 =  v1 instanceof Car;          // false
            boolean result5 =  v2 instanceof Vehicle;    // true
            boolean result6 =  v2 instanceof Car;          // true
     
            System.out.println(result1);
            System.out.println(result2);
            System.out.println(result3);
            System.out.println(result4);
            System.out.println(result5);
            System.out.println(result6);
       }
    }

    从执行结果来看,虽然 v2 被声明为了 Vehicle(父类),但它既是 instanceof Vehicle,又是 instanceof Car,所以 v2 其实是 Car(子类),否则 v2 instanceof Car 应该为 false。

    Java增强for循环

    Java5 引入了一种主要用于数组的增强型 for 循环。

    Java 增强 for 循环语法格式如下:

    for(声明语句 : 表达式) 
    { 
        //代码句子 
    }

    声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。

    表达式:表达式是要访问的数组名,或者是返回值为数组的方法。

    实例

    Test.java 文件代码:

    public class Test {
       public static void main(String args[]){
          int [] numbers = {10, 20, 30, 40, 50};
     
          for(int x : numbers ){
             System.out.print( x );
             System.out.print(",");
          }
          System.out.print("
    ");
          String [] names ={"James", "Larry", "Tom", "Lacy"};
          for( String name : names ) {
             System.out.print( name );
             System.out.print(",");
          }
       }
    }

    以上实例编译运行结果如下:

    10,20,30,40,50,
    James,Larry,Tom,Lacy,

    Number & Math类

    所有的包装类IntegerLongByteDoubleFloatShort都是抽象类Number的子类。

    这种由编译器特别支持的包装称为装箱,所以当内置数据类型被当作对象使用的时候,编译器会把内置类型装箱为包装类。相似的,编译器也可以把一个对象拆箱为内置类型。Number类属于java.lang包。

    下面的表中列出的是 Number & Math 类常用的一些方法:

    序号方法与描述
    1 xxxValue()
    将 Number 对象转换为xxx数据类型的值并返回。
    2 compareTo()
    将number对象与参数比较。
    3 equals()
    判断number对象是否与参数相等。
    4 valueOf()
    返回一个 Number 对象指定的内置数据类型
    5 toString()
    以字符串形式返回值。
    6 parseInt()
    将字符串解析为int类型。
    7 abs()
    返回参数的绝对值。
    8 ceil()
    对整形变量向上取整,返回类型为double型。
    9 floor()
    对整型变量向下取整。返回类型为double类型。
    10 rint()
    返回与参数最接近的整数。返回类型为double。
    11 round()
    返回一个最接近的int、long型值。
    12 min()
    返回两个参数中的最小值。
    13 max()
    返回两个参数中的最大值。
    14 exp()
    返回自然数底数e的参数次方。
    15 log()
    返回参数的自然数底数的对数值。
    16 pow()
    返回第一个参数的第二个参数次方。
    17 sqrt()
    求参数的算术平方根。
    18 sin()
    求指定double类型参数的正弦值。
    19 cos()
    求指定double类型参数的余弦值。
    20 tan()
    求指定double类型参数的正切值。
    21 asin()
    求指定double类型参数的反正弦值。
    22 acos()
    求指定double类型参数的反余弦值。
    23 atan()
    求指定double类型参数的反正切值。
    24 atan2()
    将笛卡尔坐标转换为极坐标,并返回极坐标的角度值。
    25 toDegrees()
    将参数转化为角度。
    26 toRadians()
    将角度转换为弧度。
    27 random()
    返回一个随机数。

    常用类:

    1. Character类

    Character 类用于对单个字符进行操作。

    Character 类在对象中包装一个基本类型 char 的值

    char ch = 'a';
    // Unicode 字符表示形式
    char uniChar = 'u039A'; 
    // 字符数组
    char[] charArray ={ 'a', 'b', 'c', 'd', 'e' };
     Character ch = new Character('a');
    1 isLetter()
    是否是一个字母
    2 isDigit()
    是否是一个数字字符
    3 isWhitespace()
    是否是一个空格
    4 isUpperCase()
    是否是大写字母
    5 isLowerCase()
    是否是小写字母
    6 toUpperCase()
    指定字母的大写形式
    7 toLowerCase()
    指定字母的小写形式
    8 toString()
    返回字符的字符串形式,字符串的长度仅为1

    2. String类

    String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了

    如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类

    1. 字符串长度

    public class StringDemo {
        public static void main(String args[]) {
            String site = "www.runoob.com";
            int len = site.length();
            System.out.println( "长度 : " + len );
       }
    }

    以上实例编译运行结果如下:

    长度 : 14

    2. 创建格式化字符串

    String 类使用静态方法 format() 返回一个String 对象而不是 PrintStream 对象。

    String 类的静态方法 format() 能用来创建可复用的格式化字符串,而不仅仅是用于一次打印输出。

    如下所示:

    String fs;
    fs = String.format("浮点型变量的值为 " +
                       "%f, 整型变量的值为 " +
                       " %d, 字符串变量的值为 " +
                       " %s", floatVar, intVar, stringVar);

    3. String 类是不可改变的解析

    例如:

    String s = "Google";
    System.out.println("s = " + s);
    
    s = "Runoob";
    System.out.println("s = " + s);

    输出结果为:

    Google
    Runoob

    从结果上看是改变了,但为什么门说String对象是不可变的呢?

    原因在于实例中的 s 只是一个 String 对象的引用,并不是对象本身,当执行 s = "Runoob"; 创建了一个新的对象 "Runoob",而原来的 "Google" 还存在于内存中。

    4. length()方法,length属性和size()的方法的区别:

    • 1.length()方法是针对字符串来说的,要求一个字符串的长度就要用到它的length()方法;
    •  2.length属性是针对Java中的数组来说的,要求数组的长度可以用其length属性;
    •  3.java中的size()方法是针对泛型集合说的,如果想看这个泛型有多少个元素,就调用此方法来查看!

    这个例子来演示这两个方法和一个属性的用法:

    public static void main(String[] args) {
        String []list={"ma","cao","yuan"};
        String a="macaoyuan";
        System.out.println(list.length);
        System.out.println(a.length());
        List array=new ArrayList();
        array.add(a);
        System.out.println(array.size());
    }

    输出的值为:

    3
    9
    1

    5. 下面是 String 类支持的方法:

    1 char charAt(int index)
    返回指定索引处的 char 值。
    2 int compareTo(Object o)
    把这个字符串和另一个对象比较。
    3 int compareTo(String anotherString)
    按字典顺序比较两个字符串。
    4 int compareToIgnoreCase(String str)
    按字典顺序比较两个字符串,不考虑大小写。
    5 String concat(String str)
    将指定字符串连接到此字符串的结尾。
    6 boolean contentEquals(StringBuffer sb)
    当且仅当字符串与指定的StringButter有相同顺序的字符时候返回真。
    7 static String copyValueOf(char[] data)
    返回指定数组中表示该字符序列的 String。
    8 static String copyValueOf(char[] data, int offset, int count)
    返回指定数组中表示该字符序列的 String。
    9 boolean endsWith(String suffix)
    测试此字符串是否以指定的后缀结束。
    10 boolean equals(Object anObject)
    将此字符串与指定的对象比较。
    11 boolean equalsIgnoreCase(String anotherString)
    将此 String 与另一个 String 比较,不考虑大小写。
    12 byte[] getBytes()
     使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
    13 byte[] getBytes(String charsetName)
    使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
    14 void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
    将字符从此字符串复制到目标字符数组。
    15 int hashCode()
    返回此字符串的哈希码。
    16 int indexOf(int ch)
    返回指定字符在此字符串中第一次出现处的索引。
    17 int indexOf(int ch, int fromIndex)
    返回在此字符串中第一次出现指定字符处的索引,从指定的索引开始搜索。
    18 int indexOf(String str)
     返回指定子字符串在此字符串中第一次出现处的索引。
    19 int indexOf(String str, int fromIndex)
    返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始。
    20 String intern()
     返回字符串对象的规范化表示形式。
    21 int lastIndexOf(int ch)
     返回指定字符在此字符串中最后一次出现处的索引。
    22 int lastIndexOf(int ch, int fromIndex)
    返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索。
    23 int lastIndexOf(String str)
    返回指定子字符串在此字符串中最右边出现处的索引。
    24 int lastIndexOf(String str, int fromIndex)
     返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索。
    25 int length()
    返回此字符串的长度。
    26 boolean matches(String regex)
    告知此字符串是否匹配给定的正则表达式。
    27 boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)
    测试两个字符串区域是否相等。
    28 boolean regionMatches(int toffset, String other, int ooffset, int len)
    测试两个字符串区域是否相等。
    29 String replace(char oldChar, char newChar)
    返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
    30 String replaceAll(String regex, String replacement
    使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
    31 String replaceFirst(String regex, String replacement)
     使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
    32 String[] split(String regex)
    根据给定正则表达式的匹配拆分此字符串。
    33 String[] split(String regex, int limit)
    根据匹配给定的正则表达式来拆分此字符串。
    34 boolean startsWith(String prefix)
    测试此字符串是否以指定的前缀开始。
    35 boolean startsWith(String prefix, int toffset)
    测试此字符串从指定索引开始的子字符串是否以指定前缀开始。
    36 CharSequence subSequence(int beginIndex, int endIndex)
     返回一个新的字符序列,它是此序列的一个子序列。
    37 String substring(int beginIndex)
    返回一个新的字符串,它是此字符串的一个子字符串。
    38 String substring(int beginIndex, int endIndex)
    返回一个新字符串,它是此字符串的一个子字符串。
    39 char[] toCharArray()
    将此字符串转换为一个新的字符数组。
    40 String toLowerCase()
    使用默认语言环境的规则将此 String 中的所有字符都转换为小写。
    41 String toLowerCase(Locale locale)
     使用给定 Locale 的规则将此 String 中的所有字符都转换为小写。
    42 String toString()
     返回此对象本身(它已经是一个字符串!)。
    43 String toUpperCase()
    使用默认语言环境的规则将此 String 中的所有字符都转换为大写。
    44 String toUpperCase(Locale locale)
    使用给定 Locale 的规则将此 String 中的所有字符都转换为大写。
    45 String trim()
    返回字符串的副本,忽略前导空白和尾部空白。
    46 static String valueOf(primitive data type x)
    返回给定data type类型x参数的字符串表示形式。

    IO流:

    如下图所示:分为两个部分,字节流(input/output)和字符流(reader/writer

    字节流就是一个字节一个字节的传(write/read只有byte接口

    字符流就是可以传送字符串数据(有String之类的接口)

    package com.hanchao.test;  
      
    import java.io.BufferedInputStream;  
    import java.io.BufferedOutputStream;  
    import java.io.File;  
    import java.io.FileInputStream;  
    import java.io.FileOutputStream;  
    
    public class Test_two {  
      
        public static void main(String[] args) throws Exception{  
              
            /** 
             * InputStream与OutputStream的使用例子 
             *  
             * (缓冲文件输入流)BufferedInputStream → (文件输入流)FileInputStream → (输入流)java.io.InputStream 
             *  
             * (缓冲文件输出流)BufferedOuputStream → (文件输出流)FileOuputStream → (输出流)java.io.OutputStream 
             */  
              
            /** 
             * 1.通过流复制一个图片的例子 
             */  
    /*      File file = new File("c:/images/1.png"); 
            File outfile = new File("C:/temp.png"); 
             
            FileInputStream inputStream = new FileInputStream(file); 
            FileOutputStream outputStream = new FileOutputStream(outfile); 
             
            int i = 0; 
            while(i != -1) { 
                i = inputStream.read(); 
                outputStream.write(i); 
            } 
            //注意流的关闭(★必须的) 
            inputStream.close(); 
            outputStream.close(); 
    */  
              
            /** 
             * 2.如果我们想提高要提高复制的速度,可以采用缓冲文件输入输出流,如下: 
             */  
    /*      File file = new File("C:/images/1.png"); 
            File outfile = new File("C:/temp1.jpg"); 
             
            //文件输入流 
            FileInputStream inputStream = new FileInputStream(file); 
            //文件输出流 
            FileOutputStream outputStream = new FileOutputStream(outfile); 
             
            //缓冲文件输入流 
            BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream); 
            //缓冲文件输出流 
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream); 
             
            int i = 0; 
            while(i != -1) { 
                i = bufferedInputStream.read(); 
                bufferedOutputStream.write(i); 
            } 
            //流的关闭 
            bufferedOutputStream.flush();//强制清除缓冲区的内容 
            bufferedInputStream.close(); 
            bufferedOutputStream.close(); 
    */  
              
            /** 
             * 3.当文件很大,我们要做一个缓冲处理来提高速度。如下:当文件的大小大于512个字节时,每次读入512个字节后再做处理 
             *  
             */  
    /*      File file = new File("C:/images/1.png"); 
            File outfile = new File("C:/temp2.png"); 
             
            //文件输入流 
            FileInputStream inputStream = new FileInputStream(file); 
            //文件输出流 
            FileOutputStream outputStream = new FileOutputStream(outfile); 
             
            int i = 0; 
            //缓冲大小为512字节 
            byte[] buffer = new byte[512]; 
            while(true) { 
                if(inputStream.available() < 512) { 
                    while(i != -1) { 
                        i = inputStream.read(); 
                        outputStream.write(i); 
                    } 
                    break;//注意此处不能忘记哦 
                } else { 
                    //当文件的大小大于512字节时 
                    inputStream.read(buffer); 
                    outputStream.write(buffer); 
                } 
            } 
             
            //流的关闭 
            //注意流的关闭(★必须的) 
            inputStream.close(); 
            outputStream.close(); 
    */  
              
            /** 
             * 4.根据上面的例子,我们可以知道:我们可以做一个双缓冲的文件复制 
             */  
            File file = new File("C:/images/1.png");  
            File outfile = new File("C:/temp3.png");  
              
            //文件输入流  
            FileInputStream inputStream = new FileInputStream(file);  
            //文件输出流  
            FileOutputStream outputStream = new FileOutputStream(outfile);  
              
            //缓冲文件输入流  
            BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);  
            //缓冲文件输出流  
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);  
              
            int i = 0;  
            //缓冲区的大小  
            byte[] buffer = new byte[512];  
              
            while(true) {  
                if(bufferedInputStream.available() < 512) {  
                    while(i != -1) {  
                        i = bufferedInputStream.read();  
                        bufferedOutputStream.write(i);  
                    }  
                    break;  
                } else {  
                    //当文件的大小还大于512字节时  
                    bufferedInputStream.read(buffer);  
                    bufferedOutputStream.write(buffer);  
                      
                }  
            }  
              
            //强制清空缓冲区的内容  
            bufferedOutputStream.flush();  
            //流的关闭  
            bufferedInputStream.close();  
            bufferedOutputStream.close();  
              
        }  
    }  

     异常:

     1. 异常的方法:

    序号方法及说明
    1 public String getMessage()
    返回关于发生的异常的详细信息。这个消息在Throwable 类的构造函数中初始化了。
    2 public Throwable getCause()
    返回一个Throwable 对象代表异常原因。
    3 public String toString()
    使用getMessage()的结果返回类的串级名字。
    4 public void printStackTrace()
    打印toString()结果和栈层次到System.err,即错误输出流。
    5 public StackTraceElement [] getStackTrace()
    返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。
    6 public Throwable fillInStackTrace()
    用当前的调用栈层次填充Throwable 对象栈层次,添加到栈层次任何先前信息中。

    集合(容器):

    Java集合类: Set、List、Map、Queue使用场景梳理:推荐这个

    JAVA中几种常见集合的使用实例

     

    Collection接口是集合类的根接口,Java中没有提供这个接口的直接的实现类。但是却让其被继承产生了两个接口,就是SetList。Set中不能包含重复的元素。List是一个有序的集合,可以包含重复的元素,提供了按索引访问的方式。

    Map是Java.util包中的另一个接口,它和Collection接口没有关系,是相互独立的,但是都属于集合类的一部分。Map包含了key-value对。Map不能包含重复的key,但是可以包含相同的value。

     几种重要的接口和类简介

    1、List(有序、可重复) :ArrayList/LinkedList/Vector
    List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢。

    Vector为线程同步的数组,

    ArrayList为非线程同步的数组

    LinkedList为非线程同步的链表

    2、Set(无序、不能重复):TreeSet /HashSet 
    Set里存放的对象是无序,不能重复的,集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。

    3、Map(键值对、键唯一、值不唯一):HashMap /TreeMap
    Map集合中存储的是键值对,键不能重复,值可以重复。根据键得到值,对map集合遍历时先得到键的set集合,对set集合进行遍历,得到相应的值。

    在类集中提供了以下四种的常见输出方式:

    1)Iterator:迭代输出,是使用最多的输出方式。

    2)ListIterator:是Iterator的子接口,专门用于输出List中的内容。

    3)foreach输出:JDK1.5之后提供的新功能,可以输出数组或集合。

    4)for循环

    Collection: 

    泛型:

    参考:Java总结篇系列:Java泛型

    http://blog.csdn.net/daniel_h1986/article/details/5708605

    • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前(在下面例子中的<E>)。
    • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
    • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
    • 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
    public class GenericMethodTest
    {
       // 泛型方法 printArray                         
       public static < E > void printArray( E[] inputArray )
       {
          // 输出数组元素            
             for ( E element : inputArray ){        
                System.out.printf( "%s ", element );
             }
             System.out.println();
        }
     
        public static void main( String args[] )
        {
            // 创建不同类型数组: Integer, Double 和 Character
            Integer[] intArray = { 1, 2, 3, 4, 5 };
            Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
            Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
     
            System.out.println( "整型数组元素为:" );
            printArray( intArray  ); // 传递一个整型数组
     
            System.out.println( "
    双精度型数组元素为:" );
            printArray( doubleArray ); // 传递一个双精度型数组
     
            System.out.println( "
    字符型数组元素为:" );
            printArray( charArray ); // 传递一个字符型数组
        } 
    }

    编译以上代码,运行结果如下所示:

    整型数组元素为:
    1 2 3 4 5 
    
    双精度型数组元素为:
    1.1 2.2 3.3 4.4 
    
    字符型数组元素为:
    H E L L O 

    限制泛型的可用类型

        如果我们要限制class GenericsFoo<T>类型持有者T的范围为集合接口类型,只需使用class GenericsFoo<T extends Collection>,这样类中的泛型T只能是Collection接口的实现类,传入非Collection接口编译会出错。

    通配符泛型

        为了解决类型不能动态根据实例来确定的缺点,引入了“通配符泛型”,使得一个参数可以用来表示一组实例化后的模板。

    其中,

    “?”代表未知类型(类中的泛型

    extends关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类

    super关键字声明了类型的下界,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至Object;

    例如(Par super String) 

    在这里Par可以是Object,也就是说Par必须是String的父类或者自己本身

      

    //泛型其实就是C++里面的模板
    
    //1.在类里面使用泛型
    class Person<T> {
        private T age;
        public void setAge(T age) {
            this.age = age;
        }
        public T getAge() {
            return this.age;
        }
    }
    //3.1 子类使用泛型:子类可以继续使用泛型
    class Student<T> extends Person<T> {
    }
    //3.2 子类使用泛型:如果子类不想继续使用,则要父类指定泛型
    class Student2 extends Person<String> {
    }
    //4  接口使用泛型
    interface Person<T> {
        public void setAge(T age);
        public T getAge();
    }
    //4.1 接口未指定的泛型
    class Student<T> implements Person<T> {
        T age;
        public void setAge(T age)
        {
            this.age = age;
        }
        public T getAge() {
            return this.age;
        }
    }
    //4.2 接口指定的泛型
    class Student2 implements Person<String> {
        String age;
        public void setAge(String age)
        {
            this.age = age;
        }
        public String getAge() {
            return this.age;
        }
    }
     
    //5 泛型的上限
    /* Integer, Float */
    class Student<T extends Number> implements Person<T> {
        T age;
        public void setAge(T age)
        {
            this.age = age;
        }
        public T getAge() {
            return this.age;
        }
    }
    
    public class Generics {
        public static void main(String args[]) {
            Person<String> p = new Person<String>();
            p.setAge("3 years old");
            System.out.println(p.getAge());
    
            Person<Integer> p2 = new Person<Integer>();  //注意:泛型不能使用基本数据类型,只能使用引用类型,Integer为引用类型的int
            p2.setAge(3);
            System.out.println(p2.getAge());
    
            Person<?> p3;   //这里的?为通配符,任何类型都可以使用
            p3 = p;
            //p3.setAge("4 years");   //这一句是错的,因为不能进行设置
            p3.getAge();   //但是可以读出来
        
            printInfo2(p);
            printInfo2(p2);
            printInfo2(p3);
    
            Student<Integer> s = new Student<Integer>();
            s.setAge(10);
            printInfo(s);
    
            Student2 s2 = new Student2();
            s2.setAge("11 years");
            printInfo(s2);
    
            
    }
        //?为通配符,也就是任意类型都可以
        public static void printInfo(Person<?> p) {
            System.out.println(p.getAge());
        }
    
        //2.在方法里面使用泛型:这里多了一个<T>,表示是泛型
        public static <T> void printInfo2(Person<T> p) {
            System.out.println(p.getAge());
        }
        //6.泛型的下线:不能在定义的时候使用,只能在使用的时候使用
    public static void printInfo(Person<? super String> p) {
            System.out.println(p.getAge());
        }
    }

    反射:

    参考资料:

    JAVA中的反射机制

    java反射详解

    如下:以前都是导入类名,再new,来得到实例化对象

    现在我们可以使用反射,通过实例化对象反射得到完整的类名和包

    lesson1:

    package a.b.c.d;
    
    class Person {
        private String name;
    
        void setName(String name) { this.name = name; }
        String getName() { return this.name; }
        
    };
    
    public class Reflect {
        public static void main(String args[]) {
            Person p = new Person();
            Class<?> c1 = null;
    
            try {
                 //三种获得class的方法
                //1.1 获得class方法
                c1 = Class.forName("a.b.c.d.Person");
            } catch (ClassNotFoundException e) {
                System.out.println(e);
            }
            //1.2 获得class的方法
            Class<?> c2 = p.getClass();
            //1.3 获得class的方法
            Class<?> c3 = Person.class;
    
            System.out.println(c1.getName());
            System.out.println(c2.getName());
            System.out.println(c3.getName());
    
            int arr[] = {1,2,3};
            int arr2[][] = {{1,2,3,4},{1}};
            
            Class<?> c4 = arr.getClass();
            Class<?> c5 = arr.getClass();
    
            Class<?> c6 = int.class;
            System.out.println(c4.getName());
            System.out.println(c5.getName());
            System.out.println(c6.getName());
            System.out.println((c4 == c5));
            System.out.println((c4 == c6));
        }
    }
    【:代表是数组, I代表是整数

    lesson2:

    在acd这个目录下
    package a.b.c.d;
    
    public class Person {
        private String name;
    
        void setName(String name) { this.name = name; }
        String getName() { return this.name; }
    
        public Person() {
            System.out.println("Constructor of Person");
        }
        public Person(String name) {
            this.name = name;
            System.out.println("Constructor2 of Person, name is "+this.name);
        }
    };
    在根目录下
    使用反射则不需要再使用import了
    //import a.b.c.d.Person;
    
    import java.lang.reflect.Constructor;
    
    public class Reflect {
        public static void main(String args[]) throws Exception {
            Class<?> c = null;
    
            try {
                c = Class.forName("a.b.c.d.Person");
            } catch (ClassNotFoundException e) {
                System.out.println(e);
            }
    
            Object p = null;
    
            try {
                p = c.newInstance();
            } catch (InstantiationException e) {
                System.out.println(e);
            }
            //带参数的构造
            Constructor<?> con = c.getConstructor(String.class);
            Object p2 = con.newInstance("weidongshan");
            //获得类的方法
    Method set = c.getMethod("setName", String.class);
    //对象使用方法
            set.invoke(p2, "123");
            set.invoke(p, "abc");
    
            Method get = c.getMethod("getName");
    
            System.out.println(get.invoke(p));
            System.out.println(get.invoke(p2));
            
            //获得和设置属性:不建议用,会破坏封装性
            //获得属性:可以是公有的和私有的
    Field name = c.getDeclaredField("name");
            //获得属性:只能是公有的
    //Field name = c.getField("name");
            //设置属性为可被外部访问的,也就是public
            //name.setAccessible(true);
    
            name.set(p, "www");
            name.set(p2, "100ask");
            System.out.println(name.get(p));
            System.out.println(name.get(p2));
    }
    }

    lesson3:

    lesson3:
    在acd这个目录下再增加一个Student.java文件
    package a.b.c.d;
    
    public class Student {
        public String name;
    
        public void setName(String name) { this.name = name; }
        public String getName() { return this.name; }
    
        public Student() {
            System.out.println("Constructor of Student");
        }
        public Student(String name) {
            this.name = name;
            System.out.println("Constructor2 of Student, name is "+this.name);
        }
    };
    //根目录修改为
    public class Reflect {
        public static void main(String args[]) throws Exception {
            Class<?> c = null;
    
            try {
                c = Class.forName(args[0]);   //就修改这里,其他地方一样
            } catch (ClassNotFoundException e) {
                System.out.println(e);
            }
    
            。。。
    }

    更加不同参数或者配置文件,可以实例化不同的对象,更加增加了灵活性

     

    线程

    JAVA的线程

    文件操作

    JAVA文件操作

  • 相关阅读:
    jquery清空下拉框,保留第一个
    [转]js和jquery获取窗体高度
    点击回车 按钮不执行点击事件
    时间戳 Date.parse()和dateObject.getTime()的区别
    uni-app 时间格式问题 new Date(str) IOS系统跟Android系统不兼容
    uni-app 使用 iconfont 图标 自定义图标
    uni-app 使用Vuex+ (强制)登录
    uni-app 保持登录状态 (Vuex)
    package.json和npm install、cnpm install 的問題
    如何将baseUrl项目地址提取放到放到static
  • 原文地址:https://www.cnblogs.com/maogefff/p/7673682.html
Copyright © 2020-2023  润新知