zoukankan      html  css  js  c++  java
  • Java简明教程

    Java与C++比较概况

    C++Java
    class Foo {          // 声明 Foo 类
    public:
        int x;           // 成员变量
     
        Foo(): x(0) {    // Foo 的构造函数Constructor for Foo,
        }                //  初始化 x
     
        int bar(int i) { // 成员函数 bar()
            return 3*i + x;
        }
    };
    class Foo {               // 定义类 Foo
        public int x = 0;     // 成员变量,
                              //  以及其值的初始化
        public Foo() {        // Foo的构造函数
        }
     
        public int bar(int i) {// 成员方法 bar()
            return 3*i + x;
        }
    }
    Foo a;
    // 声明 a 为一个 Foo 类的对象值,
    // 使用其缺省的构造函数
    // 如果你想要用其他的构造函数,
    // 你可以用 "Foo a(args);"
    Foo a;
    // 声明 a 为一个 Foo 类的对象的引用
    a = new Foo();
    // 使用缺省的构造函数初始化
    // 如果你想要用其他的构造函数,
    // 你可以用 "Foo a = new Foo(args);"
    
    
    Foo b = a;
    // 拷贝 a 的内容到一个新的 Foo 类的变量 b 当中;
    // 另一种可以选择的语法是 "Foo b(a)"
    
    
    Foo b = a.clone();
    // 拷贝所有a这个实例的成员到b,当且仅当,
    // Foo 实现了一个 public 的 clone() 方法,
    // 并且 clone() 返回一个新的这个对象的拷贝
    
    
    a.x = 5; // 修改 a 对象
    
    
    a.x = 5; // 修改 a 对象
    cout << b.x << endl;
    // 输出 0,因为 b 和 a 是两个对象
    System.out.println(b.x);
    // 输出 0,因为 b 和 a 是两个对象
    Foo *c;
    // 声明 c 为指向一个 Foo 类对象的指针(初始值是
    // 未定义的;可能指向任何地方)
    Foo c;
    // 声明 c 为一个指向 Foo 对象的指针
    // (如果 c 是一个类的成员,那么初始值为空;
    // 如果 c 是一个局部变量那么你在使用之前必须
    // 对它进行初始化)
    c = new Foo();
    // 将 c 绑定为一个新的 Foo 对象的引用
    c = new Foo();
    // 将 c 绑定为一个新的 Foo 对象的引用
    Foo *d = c;
    // 将 d 绑定为和 c 同一个对象的引用
    Foo d = c;
    // 将 d 绑定为和 c 同一个对象的引用
    c->x = 5;
    // 修改 c 指向的对象
    c.x = 5;
    // 修改 c 指向的对象
    a.bar(5);  // 对 a 调用 Foo::bar()
    c->bar(5); // 对 *c 调用 Foo::bar()
    a.bar(5); // 对 a 调用 Foo.bar()
    c.bar(5); // 对 c 调用 Foo.bar()
    cout << d->x << endl;
    // 输出 5,因为 d 引用的对象和 c 一样
    System.out.println(d.x);
    // 输出 5,因为 d 引用的对象和 c 一样

    -- 来自于wiki - Comparison of Java and C++  en  中文

    Java具有如下一些特性:

    1. Java中基本数据为值类型,数组、枚举、类、接口均为引用类型。
    2. Java中没有全局变量、全局函数、没有struct,没有union,所有东西必须写入类中。
    3. Java用包代替了命名空间,用import关键字来导入外部包进行使用。
    4. Java所有对象都从Object类单根继承,支持接口多继承。
    5. Java没有预处理过程(不存在宏)、没有goto语句、没有指针、没有析构函数,不支持函数缺省参数,不支持运算符重载

    Java基本类型及其包装类

    boolean [1字节]

    boolean flag = false;

    Boolean

    Boolean bObj1 = Boolean.TRUE;
    Boolean bObj2 = new Boolean(false);

    char [2字节 16位Unicode]

    char ch1 = 'a';
    char ch2 = '141'; // 8进制,'a'
    char ch3 = 'u0061'; // 16进制,'a'
    char ch4  = '
    ';
    char ch5 = '中';

    Character

     

    Character chObj1 = new Character('a');
    char ch2 = Character.toUpperCase('b');

    byte [1字节]

    byte a = 35;

    Byte

    Byte.MIN_VALUE - Byte.MAX_VALUE

    Byte b1 = new Byte("23");

    short [2字节]

    short a = 870;

    Short

    Short.MIN_VALUE - Short.MAX_VALUE

    Short s1 = new Short("315");

    int [4字节]

    int a = 56;  // 十进制
    int b = 0210; // 八进制
    int c = 0x2ff;  // 十六进制

    Integer

    Integer.MIN_VALUE - Integer.MAX_VALUE

    Integer intObj = new Integer(56);
    int intVal = intObj.intValue();

    long [8字节]

    long m = 356;
    long n = 86L;

    Long

    Long.MIN_VALUE - Long.MAX_VALUE

    Long s1 = new Long("-98166");

    float [4字节]

    float f = 3.5f;

    Float

    Float.MIN_VALUE - Float.MAX_VALUE

    Float.NEGATIVE_INFINITY - Float. POSITIVE_INFINITY

    0.0f/0.0f   Float.NaN

    double [8字节]

    double d1 = 2.56;
    double d2 = 2.3e-2

    Double

    Double.MIN_VALUE - Double.MAX_VALUE

    Double.NEGATIVE_INFINITY- Double. POSITIVE_INFINITY

    0.0/0.0    Double.NaN

    基本类型的大小固定,与平台无关,因此Java没有像C++那样提供sizeof关键字来获取类型和对象的大小。

    另外,Java不提供无符号的数据类型(unsigned)。

    右移位运算符>>>

    与逻辑右移位运算符功能类似,只是在左端末尾插入零值。>>则会在移位的同时插入符号位(即算术移位)

    int n1 = -1;      //n1=0xFFFFFFFF
    int n2 = n1>>1;   //n2=0xFFFFFFFF
    int n3 = n1>>>1;  //n3=0x7FFFFFFF

    函数参数传递

    Java函数参数没有指针传递、引用传递,只有值传递。

    值类型参数会产生一个值类型副本,引用类型参数会产生一个引用类型副本(注意:引用类型间赋值不会产生新的对象,因此不会触发拷贝构造函数调用)

    因此,想通过函数来实现两个数值变量或对象的交换是不行的,如下:

    /***** AppMain.java *****/
    public class AppMain 
    {
        public static void fun(int n, Integer o)
        {
            n = 1;
            o = new Integer(1);
        }
        
        public static void swapInt(int a, int b)
        {
            int c = a;
            a = b;
            b = c;
        }
        
        public static void swapInteger(Integer oa, Integer ob)
        {
            Integer oc = oa;
            oa = ob;
            ob = oc;
        }
        
        public static void main(String[] args) 
        {
            int n1 = 0;
            Integer on1 = new Integer(0);
            System.out.println("n1="+n1 + ", on1="+on1);//n1=0, on1=0
            fun(n1, on1);
            System.out.println("n1="+n1 + ", on1="+on1);//n1=0, on1=0
            
            int n2 = 1;
            Integer on2 = new Integer(1);
            System.out.println("n1="+n1 + ", n2="+n2); //n1=0, n2=1
            System.out.println("on1="+on1 + ", on2="+on2);//on1=0, on2=1
            swapInt(n1, n2);
            swapInteger(on1, on2);
            System.out.println("n1="+n1 + ", n2="+n2); //n1=0, n2=1
            System.out.println("on1="+on1 + ", on2="+on2);//on1=0, on2=1
        }
    }

    其实,通过函数来实现两个数值变量或对象的交换也是有办法的(包裹:将要交换的数值变量或对象包裹到一个数组或类中)

    /***** AppMain.java *****/
    public class AppMain 
    {
        public static void swapIntTrue(int[] a, int[] b)
        {
            int c = a[0];
            a[0] = b[0];
            b[0] = c;
        }
        
        public static void swapIntegerTrue(Integer[] oa, Integer[] ob)
        {
            Integer oc = oa[0];
            oa[0] = ob[0];
            ob[0] = oc;
        }
        
        public static void main(String[] args) 
        {
            int n1 = 0;
            int n2 = 1;
            Integer on1 = new Integer(0);
            Integer on2 = new Integer(1);
            
            int nArray1[] = new int[1];
            int nArray2[] = new int[1];
            nArray1[0] = n1;
            nArray2[0] = n2;
            System.out.println("n1="+n1 + ", n2="+n2);//n1=0, n2=1
            swapIntTrue(nArray1, nArray2);
            n1 = nArray1[0];
            n2 = nArray2[0];
            System.out.println("n1="+n1 + ", n2="+n2);//n1=1, n2=0
            
            Integer onArray1[] = new Integer[1];
            Integer onArray2[] = new Integer[1];
            onArray1[0] = on1;
            onArray2[0] = on2;
            System.out.println("on1="+on1 + ", on2="+on2);//on1=0, on2=1
            swapIntegerTrue(onArray1, onArray2);
            on1 = onArray1[0];
            on2 = onArray2[0];
            System.out.println("on1="+on1 + ", on2="+on2);//on1=1, on2=0
        }
    }

    自动封装(Autoboxing)&自动拆封(Autounboxing)

    /***** AppMain.java *****/
    public class AppMain 
    {
        public static int autoBoxing(Integer o)
        {
            int sum = 2 + o;//自动拆封
            return sum;
        }
        
        public static Integer autoUnBoxing(int n)
        {
            Integer o = new Integer(n);
            o += 2;//自动封装
            return o;
        }
        
        public static void main(String[] args) 
        {
            Integer oRet = autoBoxing(1);//参数与返回值均自动封装
            
            int nRet = autoUnBoxing(oRet);//参数与返回值均自动拆封
        }
    }

    数组

    // -----------------  一维数组  ------------------
    int nScores[] = {1,2,3,4,5,6,7,8,9,0};
    String[] strContents = {"How", "Are", "You","?"};
    float fDistances[] = new float[3];
    
    // -----------------  二维数组  ------------------
    int nMatrix[][] = {
        {0, 1, 2},
        {3, 4, 5},
        {6, 7, 8}
    };
    double[][] codes = new double[5][5];
    
    long[] secs[] = new long[2][];
    secs[0] = new long[3];
    secs[1] = new long[4];
    
    // -----------------  数组长度  ------------------
    int nWeek[] = {1, 2, 3, 4, 5, 6, 7};
    int nLength = nWeek.length; // nLength = 7
    
    // -----------------  数组拷贝  ------------------
    int nScores[] = {1,2,3,4,5,6,7,8,9,0};
    int nScores2[] = new int[12];
    System.arraycopy(nScores, 0, nScores2, 2, 8); // nScores2 = { 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0,}

    Arrays为数组的公用工具类,里面有大量静态成员函数供数组使用。

    注释

    // 单行注释
    /* 块注释 */ 
    /** doc注释(会被javadoc辨别)*/

    package与import

    package是Java提供的一种封装机制,可将一组类和接口封装在一个package中,缺省访问符修饰的类/接口、变量、方法在package内可见。package有效地管理类名空间,可防止类名冲突。

    package语句作为Java源文件的第一条语句,指明该文件中定义的类/接口所在的包

    package com.JavaApp; // 该源文件需要放在src/com/JavaApp目录中

    如果源文件中没有package语句,则为无名包,该源文件存放在src/目录中

    为了防止在使用类时带上长长的包路径,可使用import将包路径导入到当前源文件中

    import java.applet.Applet;
    import java.awt.*;

    for、break、continue增强

    void breakTest()
    {
        int sum = 0;
        int[] code = {0,1,2,3,4,5};
        // 针对数组、集合、枚举的for循环形式   JDK1.5之后增加
        for (int e : code)
        {
            sum += e;
            if (sum >30)
            {
                break;
            }
        }
    
        L1:for(int i=0; i<100; i++)
        {
            L2:for(int j=0; j<100; j++)
            {
                if (i==50 && j==80)
                {
                    // 跳出L1层循环
                    break L1;
                }
            }
        }
    }
    
    void continueTest()
    {
        int sum = 0;
        while(sum<1000)
        {
            if (++sum>100)
            {
                continue;
            }
        }
    
        C1:for(int i=0; i<100; i++)
        {
            C2:for(int j=0; j<100; j++)
            {
                if (i==50 && j==80)
                {
                    // 继续C1层循环
                    continue C1;
                }
            }
        }
    }

    字符串(16位unicode)

    String  处理不变的字符串,任何对String的改变都会引发新的String对象的生成

    String s1 = "hello";            // 静态创建字符串对象
    String s2 = new String("你好"); // 动态创建字符串对象
    int ns1Len = s1.length(); // ns1Len = 5
    int ns2Len = s2.length(); // ns2Len = 2
            
    String s3 = "hello";
    String s4 = new String("你好");
            
    String s5 = "Hello";
            
    if (s1==s3)  // true  -s1与s3是否指向同一个对象
    {
        System.out.println("yes!! s1==s3");
    }
    if (s2==s4)  // false  -s2与s4是否指向同一个对象
    {
        System.out.println("yes!! s2==s4");
    }
            
    if (s1.equals(s5)) // false  -s1与s5的字符串内容是否完全一致
    {
        System.out.println("yes!! s1,s5 has same string value.");
    }
    if (s2.equals(s4)) // true  -s2与s4的字符串内容是否完全一致
    {
        System.out.println("yes!! s2,s4 has same string value.");
    }
            
    if (s1.equalsIgnoreCase(s5)) // true  -忽略大小写,s1与s5的字符内容是否一致
    {
        System.out.println("yes!! s1,s5 has same string value when ignore case.");
    }
    if (s2.equalsIgnoreCase(s4)) // true  -忽略大小写,s2与s4的字符内容是否一致
    {
        System.out.println("yes!! s2,s4 has same string value when ignore case.");
    }

    String类的"="、"+"、"+=",看似运算符重载,实际只是java编译器做了一点手脚,对String的运算符做了特殊处理。

    String s = "Hello ";
    s += "World!"; // 编译器转换成s = (new StringBuilder()).append(s).append("World!").toString();

    StringBuffer   处理可变字符串(线程安全),不可被继承(final)

    StringBuilder  处理可变字符串(线程不安全,拥有更高的性能),不可被继承(final),JDK1.5引入

    StringBuffer与StringBuilder在使用上几乎没有区别

    StringBuffer sb1 = new StringBuffer("Hello ");
    sb1.append("World!");
    String str1 = sb1.toString(); // Hello World!
    
    StringBuilder sb2 = new StringBuilder("Hello ");
    sb2.append("World!");
    String str2 = sb2.toString(); // Hello World!

    成员权限控制

    ---------------------------- 访问修饰符 ---------------------------

        #          当前类    同一package   子类     其他package 

    public           √            √             √              √ 

    protected     √            √             √              × 

    缺省             √             √             ×             × 

    private         √             ×             ×             ×

    ---------------------------------------------------------------------

    访问修饰符 修饰符 class 类名称 extends 父类名称 implement 接口名称1, 接口名称2

    1、每个类文件仅能有一个public class,可以存在多个其他的缺省class 
    2、public class的名称(包含大小写)必须和其类文件同名
    3、一个类文件(*.java)中可以不存在public class
    4、top class不能是private和protected(注:内部类可以)

    修饰符:

    final 当前类不能被继承
    abstract 抽象类,不能被实例化;抽象类中不一定包含抽象方法,但包含了抽象方法的类一定要声明为抽象类
    static 静态类;只有内部类才能定义为静态类

    内部类
    1、内部类拥有top class的所有特性
    2、内部类可以是public、缺省、protected、private的
    3、内部类可以访问其外部类的成员变量、方法,及所在外部类的其它内部类

    静态类
    1、只有内部类才能声明为static,也可以说是静态内部类
    2、只有静态内部类才能拥有静态成员,普通内部类只能定义普通成员
    3、静态类跟静态方法一样,只能访问其外部类的静态成员
    4、如果在外部类的静态方法中访问内部类,这时候只能访问静态内部类

    其他类中使用内部类
    1、访问内部类,必须使用:外部类.内部类
    2、静态内部类可以直接new
    3、普通内部类必须绑定在其外部类的实例上

    class A 
    {
    static class Ainner1 {} class Ainner2 {} } class B { public test() { A.Ainner1 m1 = new A.Ainner1(); A m = new A(); A.Ainner2 m2 = m.new Ainner2(); } }

    [静态] 成员变量

    class A 
    {
        // 调用顺序 【1】
        public static int MAX_SIZE = 100;
        static final int WTN_TOTAL = 500; // static常量类型,定义时必须进行初始化
        public int m_nVar = 9;
        final boolean m_switch = false; // 常量类型,定义时进行初始化
        final int m_nVarConst;  // final空白(只声明,不赋值),可在构造函数中为不同对象赋不同的值
    
        protected String m_strName = "A";
        private boolean m_bSex;
    
        float m_fDis = 8.0f;
    
        transient short m_shFlag = 10; // 告诉编译器,在类对象序列化的时候,此变量不需要持久保存
        public static volatile boolean m_bRet; // 多线程时,要求编译器优化时保证对此变量的修改能够被正确的处理
    
        // 调用顺序 【2】
        // 类成员变量初始化器,可以有多个,按照先后顺序执行,但仅被初始化一次(当JVM加载类时执行)
        static
        {
            MAX_SIZE = 240;
        }
        static
        {
        }
    
        // 成员变量初始化器;运行于父类构造函数之后,自身构造函数之前
        {
            m_nVar = 100;
            m_strName = "AA";
            m_bSex = false;
            m_fDis = 12.0f;
        }
    
        // 调用顺序 【3】
        public A()
        {
            MAX_SIZE = 200;
            m_nVar = 99;
            m_strName = "a";
            m_bSex = true;
            m_fDis = 10.0f;
            // final空白,必须在构造函数中赋初值
            m_nVarConst = 0;
        } 
    
        public A(int nVar)
        {
            // final空白,必须在构造函数中赋初值
            // 可在构造函数中为不同对象赋不同的值
            // 一旦被赋值,就不可再改变
            m_nVarConst = nVar;
        } 
    
        // 参数nVar1不可在函数体中被修改
        public void fun1(final int nVar1, int nVar2)
        {
            // nSum被赋值后不能被修改
            final int nSum = nVar1 + nVar2;
    
            // static int nResult = 100;  -- 非法,java不允许static局部变量
        }
    }

    [静态] 成员函数

    class B 
    {
        int m_nVar = 0;
        static short m_shVar = 10;
    
        // 无参构造函数
        public B()
        {
            m_nVar = 1;
        }
        // 有参构造函数
        public B(int nVar)
        {
            m_nVar = nVar;
        }
        // 拷贝构造函数
        public B(B other)
        {
            this.m_nVar = other.m_nVar;
        }
        // finalize方法调用时机
        // 1、显式的调用finalize方法
        // 2、程序退出时为每个对象调用一次finalize方法
        // 3、JVM按照某种策略(如内存不够)来进行垃圾回收时调用finalize;程序员可通过调用System.gc()来建议JVM进行垃圾回收
        protected void finalize()
        {
        }
    
        // final类成员函数,不能被子类重写
        // 在其函数体内,只能访问类成员变量和类成员函数,不能使用this、super等关键字
        public final static void sFunc1()
        {
            m_shVar = 5;
        }
    
        // 类成员函数;在其函数体内,只能访问类成员变量和类成员函数,不能使用this、super等关键字
        public static void sFunc2(int nVar)
        {
            m_shVar += nVar;
        }
        // final成员函数,可被子类继承,但不能被重写
        public final void func1(int nVar)
        {
            m_shVar = (short)nVar;
            m_nVar = nVar;
        }
    
        // 成员函数
        public void func2(int nVar)
        {
            m_shVar = (short)nVar;
            m_nVar = nVar;
    
            // 调用参数不定成员函数
            fun3();
            fun3(1);
            fun3(1,2);
            fun3(1,2,3);
            fun3(new int[]{1,2});
        }
    
        // 参数不定成员函数
        // 1、如果存在fun3()、fun3(int)等函数,在调用fun3时,优先匹配定长参数的函数
        // 2、可变参数必须为函数参数列表中的最后一项
        public void fun3(int... an) 
        { 
            for(int i=0;i<an.length;i++) 
            { 
                System.out.println(an[i]);
            } 
        }
    
        // java native方法及JNI实例
        // 用native定义的方法没有实现,而大多数情况下该方法的实现是用C、C++编写的
        // JNI提供了运行时加载一个native方法的实现,并将其于一个Java类关联的功能
        public native void displayHelloWorld();
    
        /*1、synchronized关键字的作用域有二种: 
        1)对象实例范围。synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法
        (如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。
        然而,不同的对象实例的synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法; 
        2)类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static方法
        (如果一个类有多个synchronized static方法,只要一个线程访问了其中的一个synchronized static方法,其它线程不能同时访问这个类中任何一个synchronized static方法)。
        它可以对类的所有对象实例起作用。
    
        2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。
        用法是: 
        synchronized(B.class){区块},它的作用域是类B; 
        synchronized(this){区块},它的作用域是当前this对象; 
        synchronized(String obj){区块},它的作用域是当前String对象;
    
        3、synchronized关键字不能被继承的,也就是说,基类的synchronized f()方法在继承类中并不自动是synchronized f(),而是变成了f()。
        继承类需要显式的指定为synchronized方法。*/
    
        // synchronized static 方法
        public static synchronized void synFunc1()
        {
        }
        // synchronized方法
        public synchronized void synFunc2()
        {
        }
        // synchronized块
        public void synFun3(String strVar)
        {
            // 获得当前类锁。有线程访问时以下同步代码块时,其它线程的访问都被暂时阻塞
            synchronized(B.class) 
            { 
                System.out.println("syn class!"); 
            }
        
            System.out.println("Hello..."); 
    
            // 获得当前strVar对象锁。有线程访问时以下同步代码块时,其它线程的访问都被暂时阻塞
            synchronized(strVar) 
            { 
                System.out.println("syn var obj!"); 
            }
    
            System.out.println("World..."); 
    
            // 获得当前this对象锁。有线程访问时以下同步代码块时,其它线程的访问都被暂时阻塞
            synchronized(this) 
            { 
                System.out.println("syn this!"); 
            }
        }
    }
    
    // 抽象函数
    abstract class C
    {
        // 不能将static方法、final方法或者类的构造器方法声明为abstract
        public abstract void aFunc();
    
        public int func(int a, int b)
        {
            return a+b;
        }
    }
    
    // 抽象类不能实例化,被其他类继承后,必须实现抽象类中的抽象函数
    class D extends C
    {
        public void aFunc()
        {
        }
    }

    类继承

    class CParent
    {
        String m_strName = "Parent";
        int m_nParentAge;
        
        public CParent(int nAge)
        {
            m_nParentAge = nAge;
        }
        
        public void fun1()
        {
        }
        
        public void fun2()
        {    
        }
    }
    
    class CChildren1 extends CParent
    {
        // CParent中的m_strName变量被隐藏
        String m_strName = "Children";
        int m_nChildrenAge;
        
        public CChildren1(int nAge)
        {
            // 由于父类没有缺省参数的构造函数,必须在构造函数中显示构造父类
            super(nAge);
        }
        
        // 重写CParent中的fun1方法
        // 1.重写的方法(子类)不能比被重写的方法(父类)有更严格的访问权限
        // 2.重写的方法(子类)不能比被重写的方法(父类)产生更多的异常
        public void fun1()
        {
            // this用来引用当前对象,super用来引用当前对象的父类
    
            // 强制调用CParent的fun1方法
            super.fun1();
            // 强制访问CParent的m_strName
            String str1 = super.m_strName;
            
            // 访问自己的m_strName
            String str2 = this.m_strName;
            // 访问自己的m_strName时,可以不带上this
            String str3 = m_strName;
        }
    }
    
    class CChildren2 extends CParent
    {
        public CChildren2(int nAge)
        {
            super(nAge);
        }
    }
    
    class CGrandChildren1 extends CChildren1
    {
        public CGrandChildren1(int nAge)
        {
            super(nAge);
        }
    }
    
    public class AppMain
    {
        // instanceof可以判定一个对象是否属于某个类的实例
        // 在判定时应循序特殊到一般的原则,先判断子类,再判断父类
        static int GetClassType(CParent obj)
        {
            if (obj instanceof CGrandChildren1)
            {
                return 11;
            }
            else if (obj instanceof CChildren1)
            {
                return 1;
            }
            else if (obj instanceof CChildren2)
            {
                return 2;
            }
            
            return 0;
        }
    
        public static void main(String[] args) 
        {    
            CParent c1 = new CChildren1(0);
            CParent c2 = new CGrandChildren1(0);
            int nClsType = GetClassType(c1); // 返回1
            nClsType = GetClassType(c2); // 返回11
    
            // 将c1强制转成CChildren1类型,这个过程叫造型
            /* 如果c1为CChildren1类型时,代码不会有问题;若不是,系统会抛出ClassCastException的异常
               因此,在造型之前使用instanceof进行判断是明智之举 */
            CChildren1 cc = (CParent)c1;
        }
    }

    接口

    访问修饰符 interface 接口名称 extends 接口名称1, 接口名称2

    访问修饰符:public  缺省

    与类一样,public接口必须定义到自己独立的源文件中或类的内部,缺省接口可定义在任何位置

    1、interface中数据成员均为公共类常量,具有public、static、final属性
    2、interface中方法成员均为公共抽象方法,具有public、abstract属性
    3、在接口继承关系中,如果子接口中定义了与父接口同名的常量和相同的方法,则父接口中的常量将被隐藏,方法被重写

    interface E
    {
        int MAX_SIZE = 100;
        String NAME = "E";
    
        void inter();
        void interE();
    }
    
    // 接口F必须写到F.java中
    public interface F extends E
    {
        String NAME = "F";  // 接口E的NAME被隐藏
    
        void inter();  // 接口E的inter()方法被重写
        void interF();
    }
    
    // 使用接口E,在new时重写接口E的方法
    public static void main(String[] args) 
    {
        E e = new E() 
        {
            public void interE() 
            {
            }
        };
    }

    枚举

    枚举从JDK1.5才引进;与类一样,public枚举必须定义到自己独立的源文件中或类的内部,其他类型的枚举可定义在任何位置。

    枚举具有类的绝大数特性,但也有一些特殊之处:

    1、枚举常量具有public、static、final属性
    2、枚举的构造函数必须为private
    3、无法在外部或枚举内部new一个枚举对象
    4、不支持类继承,支持接口多继承

    public enum Week {Monday, Tuesday, Wednesday, Thursday,  Friday, Saturday, Sunday};
    ////////////////////////////////////////////////////////////////////////
    enum Currency 
    {
        Penny(1), Nickle(5), Dime(12), Quarter(100);
        private int m_nValue;
    
        private Currency(int nVal)
        {
            m_nValue = nVal;
        }
        int GetValue()
        {
            return m_nValue;
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    interface IBase1
    {
        void fun1();
    }
    
    interface IBase2
    {
        void fun2();
    }
    enum Planet implements IBase1, IBase2
    {
        Mercury (3.303e+23, 2.4397e6),
        Venus   (4.869e+24, 6.0518e6),
        Earth   (5.976e+24, 6.37814e6),
        Mas    (6.421e+23, 3.3972e6),
        Jupiter (1.9e+27,   7.1492e7),
        Saturn  (5.688e+26, 6.0268e7),
        Uranus  (8.686e+25, 2.5559e7),
        Neptune (1.024e+26, 2.4746e7);
    
        private final double m_mass;
        private final double m_radius;
        Planet(double mass, double radius) 
        {
            m_mass = mass;
            m_radius = radius;
        }
        
        public void fun1()
        {
        }
        public void fun2()
        {
        }
    }
    
    ////////////////////////////////////////////////////////////////////////
    public static void main(String[] args) 
    {
        Currency usCoin = Currency.Dime;
        switch (usCoin) 
        {
             case Currency.Penny:
                 System.out.println("Penny");
                 break;
             case Currency.Nickle:
                 System.out.println("Nickle");
                 break;
             case Currency.Dime:
                 System.out.println("Dime");
                 break;
             case Currency.Quarter:
                 System.out.println("Quarter");
                 break;
        }
    
        if (Currency.Quarter == usCoin)
        {
            System.out.println("Quarter coin");
        }
    
        for(Currency coin: Currency.values())
        {
            System.out.println("coin: " + coin);
        }
    }

    异常

    所有的异常类必须从Throwable派生,异常分为两大类:一类是unchecked异常(橙色部分):
    1、Error类异常由JVM生成并抛出(如:动态链接错误),我们不能在编程层面上解决Error,所以应该直接退出程序。
    2、RuntimeException(及其衍生类)是Java程序自身造成的,RuntimeException完全可以通过修正Java程序避免。这类异常,Java编译器不强制要求程序员对其捕获和处理。

    另外一类就是checked异常(淡蓝色部分):
    Java编译器要求程序员必须捕获或声明所有的这类非运行时异常(如:文件找不到造成的IOException)。

    /******************* 自定义异常 *******************/
    class ExceptionSelf1Base extends Exception
    {
        private String m_strExpInfo;
        ExceptionSelf1Base(String strVal)
        {
            m_strExpInfo = strVal;
        }
        
        public String toString()
        {
            return "Exception: " + m_strExpInfo;
        }
    }
    
    class ExceptionSelf2Base extends Exception
    {
        private int m_nExpInfo;
        ExceptionSelf2Base(int nVal)
        {
            m_nExpInfo = nVal;
        }
        
        public String toString()
        {
            return "Exception: " + m_nExpInfo;
        }
    }
    
    class ExceptionSelf1 extends ExceptionSelf1Base
    {
        public ExceptionSelf1(String strVal)
        {
            super(strVal);
        }
    }
    /******************* 抛出异常 *******************/
    class ExceptionTest
    {
        // 需要通过throws关键字声明函数内的所有抛出的checked异常
        public void throwExp(int nMode) throws ExceptionSelf1,ExceptionSelf1Base,ExceptionSelf2Base
        {
            if (nMode < 0)
            {
                ExceptionSelf1Base e1 = new ExceptionSelf1Base("nMode < 0");
                throw e1;
            }
            else if (nMode < 100)
            {
                ExceptionSelf2Base e2 = new ExceptionSelf2Base(100);
                throw e2;
            }
            
            ExceptionSelf1 e = new ExceptionSelf1("nMode >= 100");
            throw e;
        }
    }
    /******************* 异常处理 *******************/
    public class AppMain
    {
        public static void main(String[] args) 
        {    
            ExceptionTest expTest = new ExceptionTest();
            try
            {
                expTest.throwExp(100);
            }
            // 捕捉异常时,需要按照特殊到一般的顺序进行捕捉
            catch (ExceptionSelf1 e)
            {
            }
            catch (ExceptionSelf1Base e)
            {
            }
            catch (ExceptionSelf2Base e)
            {    
            }
            catch (Exception e)
            {
            }
            // finally为非必需的块
            // 进入try块后,无论发生还是不发生异常,finally块中的代码都要被执行,提供了统一的出口
            finally
            {      
            }
        }
    }

    泛型

    泛型从JDK1.5才引进;经常被称为参数化类型,它能够像方法一样接受不同类型的参数。

    泛型中的通配符:
    (1) 泛型中可以使用"?"通配符作为参数,表示该泛型可以接受任意类型的数据
    (2) 上届通配符:只允许类A或类A的子类作为参数传入;表示方式:泛型类型<? extends A>
    (3) 下届通配符:只允许类A或类A的父类作为参数传入;表示方式:泛型类型<? super A>

    如果想从一个数据类型里获取数据,使用 ? extends A 通配符
    如果想把对象写入一个数据结构里,使用 ? super A 通配符
    如果既想存又想取,那就不要用通配符

    /***** AppMain.java *****/
    import java.util.*;
    public class AppMain 
    {
        public static void main(String[] args) 
        {
            //ArrayList<?> gList1 = new ArrayList<?>();//编译错误,通配符修饰的泛型不能用来直接创建对象
            ArrayList<String> gStrList2 = new ArrayList<String>();
            gStrList2.add("1");
            ArrayList<?> gList2 = gStrList2;
            Object objVal = gList2.get(0); //通配符修饰的泛型可以读取数据到Object类型
            //gList2.add("2"); //编译错误,【?】通配符修饰的泛型不能写入任何类型数据
            
            //ArrayList<? extends Number> geList1 = new ArrayList<? extends Number>();//编译错误,通配符修饰的泛型不能用来直接创建对象
            ArrayList<Integer> geIntList2 = new ArrayList<Integer>();
            geIntList2.add(1);
            List<? extends Number> geList2 = geIntList2;
            Object objVa2 = geList2.get(0); //通配符修饰的泛型可以读取数据到Object类型
            Number nVal = geList2.get(0); //【上届通配符】修饰的泛型可以读取数据到Number类型
            //geList2.add(new Integer(2)); //编译错误,【上届通配符】修饰的泛型不能写入任何类型数据
            
            //ArrayList<? super Integer> gsList1 = new ArrayList<? super Integer>();//编译错误,通配符修饰的泛型不能用来直接创建对象
            ArrayList<Integer> gsIntList2 = new ArrayList<Integer>();
            gsIntList2.add(1);
            List<? super Integer> gsList2 = gsIntList2;
            Object objVal3 = gsList2.get(0); //通配符修饰的泛型可以读取数据到Object类型
            //Integer nVal2 = gsList2.get(0); //编译错误,【下届通配符】修饰的泛型不能读取数据到除Object类型中
            gsList2.add(2); //【下届通配符】修饰的泛型可以写入Integer及其父类类型数据
            
            /*** 自定义泛型 ***/
            //Gencs<CString,String,String> gen1 = new Gencs<Float,String,String>();//编译错误,参数1必须为Number或其子类
            Gencs<Integer,String,String> gen2 = new Gencs<Integer,String,String>();
            Gencs<Float,String,String> gen3 = new Gencs<Float,String,String>();
            gen3.setX(3.0f);
            Float fGen3 = gen3.getX();
            Object oGen3 = gen3.getX();
            //Integer iGen3 = gen3.getX();//编译错误,返回值为Float类型
            //gen3.setX(3);//编译错误,必须传入Float类型参数
        }
    }
    
    class Gencs<X extends Number, Y, Z> 
    {
        private X m_x;    
        //static Y m_y; //编译错误,不能用在静态变量中    
        public X getX() 
        {    
            return m_x;    
        }
        
        public void setX(X x)
        {
            m_x = x;
        }
        public void fun() 
        {        
            //Z z = new Z();//编译错误,不能创建对象    
        }
    }

    集合

    点框的为接口、虚线框的为抽象类、实线框的为功能类(右下角的Collections为公用工具类,里面含有大量静态成员函数供集合使用)

    集合只能容纳对象,不能容纳基本数据类型;元素通过实现Comparable接口、或提供一个实现Comparator接口的比较算法类来定义比较的规则。

    List集合是有序集合(放入的顺序与存储的顺序一致),集合中的元素可以重复,访问集合中的元素可以根据元素的索引来访问。
    Set集合是无序集合(放入的顺序与存储的顺序不一致),集合中的元素不可以重复,访问集合中的元素只能根据元素本身来访问。
    Map集合中保存key-value对形式的元素,其key对象是不允许重复的(换个角度说:key对象的合集就是一个Set集合),访问时只能根据每项元素的key来访问其value;插入时如果key存在,则替换原来的value对象。

    对象重复的含义:
    (1) 两个对象e1和e2,如果e1.equals(e2)为true,则认为e1和e2重复,否则认为两个对象不重复
    (2) 默认两个对象是否相等的equals方法是判断两个对象变量引用值是否指向同一个地址空间,我们可以重写equals方法来自定义重复的含义

    ArrayList线程不安全;Vector线程安全(如果是单线程程序,推荐使用ArrayList
    ArrayList通过数组实现,LinkedList通过链表实现(不涉及到插入、删除等操作,推荐使用ArrayList
    HashSet相比,TreeSet会对容器内的元素进行排序;同理,相比HashMapTreeMap也会对容器内的元素进行排序
    HashMap线程不安全,键与值都可以为null;Hashtable线程安全,键与值不能为null(如果是单线程程序,推荐使用HashMap

    /***** AppMain.java *****/
    import java.util.*;
    public class AppMain 
    {
        public static void main(String[] args) 
        {
            /* ArrayList */
            List list = new ArrayList();
            list.add(new Integer(1));
            list.add("2");
            list.add(new Short((short)3));
            ListIterator iList = list.listIterator();
            while(iList.hasNext())
            {
                System.out.println(iList.next());
            }
            
            /* HashSet */
            Set hSet = new HashSet();
            hSet.add("1");
            hSet.add(new Integer(2));
            hSet.add("3");
            Iterator iHSet = hSet.iterator();
            while(iHSet.hasNext())
            {
                System.out.println(iHSet.next());
            }
            
            /* TreeSet */
            Set tSet = new TreeSet();
            tSet.add("1");
            //tSet.add(new Integer(2)); //运行时错误,TreeSet会对元素进行排序,因此需要实现插入元素间相互比较的Comparable接口
            tSet.add("3");
            Iterator iTSet = tSet.iterator();
            while(iTSet.hasNext())
            {
                System.out.println(iTSet.next());
            }
            
            /* HashMap */
            HashMap hm = new HashMap();
            hm.put(null, 0);
            hm.put("1", null);
            hm.put(new Integer(2), "2");
            hm.put("3", new Float(3.0f));
            Set sHm = hm.keySet();
            Iterator iHm = sHm.iterator();
            while(iHm.hasNext())
            {
                Object k = iHm.next();
                Object v = hm.get(k);
                System.out.println(k + "=" + v);
            }
            
            /* Hashtable */
            Hashtable ht = new Hashtable();
            // ht.put(null, 0);  //运行时错误
            // ht.put("1", null); //运行时错误
            ht.put(new Integer(2), "2");
            ht.put("3", new Float(3.0f));
            Enumeration e = ht.keys();
            while(e.hasMoreElements())
            {
                Object k = e.nextElement();
                Object v = ht.get(k);
                System.out.println(k + "=" + v);
            }
            
            /* TreeMap */
            TreeMap tm = new TreeMap();
            tm.put("1", new Long(1));
            tm.put("2", new Double(2.0));
            // tm.put(new Integer(3), "3");  //运行时错误,TreeMap会按照Key进行排序,因此Key需要实现插入元素间相互比较的Comparable接口
            Set sTm = tm.keySet();
            Iterator iTm = sTm.iterator();
            while(iTm.hasNext())
            {
                Object k = iTm.next();
                Object v = tm.get(k);
                System.out.println(k + "=" + v);
            }
        }
    } 

    以上的示例为非泛型实现的集合,现在已不推荐使用了。(由于使用集合中的元素时,必须进行造型操作,效率低;而且造型操作可能在程序运行时出现问题)

    泛型实现的集合在定义容器时,同时定义容器中对象的类型,这就使得容器内的元素只能是该对象类型或其子对象类型。

    泛型实现的集合拥有与非泛型实现的集合同样的特性,一致的外部接口。(ArrayList  LinkedList  HashSet  TreeSet  HashMap  TreeMap  Hashtable

    /***** AppMain.java *****/
    import java.util.*;
    public class AppMain 
    {
        public static void main(String[] args) 
        {
            /* ArrayList */
            List<String> list = new ArrayList<String>();
            list.add("1");
            list.add("2");
            list.add("3");
            ListIterator<String> iList = list.listIterator();
            while(iList.hasNext())
            {
                System.out.println(iList.next());
            }
            
            /* HashSet */
            Set<Integer> hSet = new HashSet<Integer>();
            hSet.add(1);
            hSet.add(new Integer(2));
            hSet.add(new Integer(3));
            Iterator<Integer> iHSet = hSet.iterator();
            while(iHSet.hasNext())
            {
                System.out.println(iHSet.next());
            }
            
            /* TreeSet */
            Set<String> tSet = new TreeSet<String>();
            tSet.add("1");
            //tSet.add(new Integer(2)); //编译时错误
            tSet.add("3");
            Iterator<String> iTSet = tSet.iterator();
            while(iTSet.hasNext())
            {
                System.out.println(iTSet.next());
            }
            
            /* HashMap */
            HashMap<String, Integer> hm = new HashMap<String, Integer>();
            hm.put(null, 0);
            hm.put("1", null);
            hm.put("2", new Integer(2));
            hm.put("3", new Integer(3));
            Set<String> sHm = hm.keySet();
            Iterator<String> iHm = sHm.iterator();
            while(iHm.hasNext())
            {
                String k = iHm.next();
                Integer v = hm.get(k);
                System.out.println(k + "=" + v);
            }
            
            /* Hashtable */
            Hashtable<String, Integer> ht = new Hashtable<String, Integer>();
            //ht.put(null, 0);  //运行时错误
            //ht.put("1", null); //运行时错误
            ht.put("2", new Integer(2));
            ht.put("3", 3);
            Enumeration<String> e = ht.keys();
            while(e.hasMoreElements())
            {
                String k = e.nextElement();
                Integer v = ht.get(k);
                System.out.println(k + "=" + v);
            }
            
            /* TreeMap */
            TreeMap<String, Integer> tm = new TreeMap<String, Integer>();
            tm.put("1", 1);
            tm.put("2", new Integer(2));
            // tm.put(new Integer(3), 3);  //编译时错误
            Set<String> sTm = tm.keySet();
            Iterator<String> iTm = sTm.iterator();
            while(iTm.hasNext())
            {
                String k = iTm.next();
                Integer v = tm.get(k);
                System.out.println(k + "=" + v);
            }
        }
    }
  • 相关阅读:
    #检查磁盘使用率超过90%,并且后台进程没有rman在跑,就运行 /data/script/del_dg_arch.sh 脚本清理归档
    linux shell数据重定向
    创建用户
    Linux HA+ Oracle 安装维护手册
    解决UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range
    Linux 文件不能被root修改与编辑原因
    python中的时间戳和格式化之间的转换
    Python-Redis-发布订阅
    Python-Redis-常用操作&管道
    Python-Redis-Set
  • 原文地址:https://www.cnblogs.com/kekec/p/3440173.html
Copyright © 2011-2022 走看看