zoukankan      html  css  js  c++  java
  • 基础知识

    编译:javac MyFirst.java
    运行:java MyFirst
    在指定目录下执行java编译clas文件:https://www.runoob.com/java/env-classpath.html
    eg:java -classpath C:javaDemoClasses HelloWorld
     
    Java程序执行流程:
    1、编写源代码文件(.java)
    2、用编译器运行源代码。编译器会检查错误,如果有错就要改正才能产生正确的输出。编译器会产生字节码(.class)。
    任何支持java的装置都能把它转译成可执行的内容。编译后的字节码与平台无关。
    3、Java虚拟机JVM读取和执行字节码。
     
    变量必须先声明并初始化以后使用。
    Java中的integer和boolean不相容,integer不能作为条件表达式
    每行代码以分好结束.
    一个Java程序至少要有一个类和一个main函数(在该类中定义)
     
    二进制浮点数移码表示法:
    整数部分和指数部分都是二进制,整数部分是小数点移动后的,指数部分是小数点移动位数的二进制表示。
    正数和负数二进制小数点左移,指数均是正数;小数点右移,指数均是负数。
    eg:
    -0.0010011=-0.10011×2^-10
    -110001101=-0.110001101×2^1001
     
    负数的二进制表示法:补码表示法
    负数二进制补码转十进制:符号位为1则表示负数,所有位取反再加1,最后在前面加上负号。
     
    负数取模方法:
    负数参与的取模运算规则:先忽略负号,按照正数运算之后,被取模的数是正数结果就取正,反之取负。
    (注:(-2)%5中被取模数是-2;-2%5中被取模数是2前面是负号)
     
    运算符优先级问题:
    x,y,z分别为5,6,7 计算z + = -- y * z++ ;// x = 5,y = 5,z = 42
    z = z + -- y * z++ ——》 42 = 7 + 5 * 7 从左到右入栈,入的是值(入)
     
    逻辑运算符的短路原则:
    int x=1,y=1,z=1; 
    if(x--==1 && y++==1 || z++==1) // || 短路运算后面的不执行了!
    System.out.println(“x=”+x+”,y=”+y+”,z=”+z);// 0 , 2, 1
     
    条件运算符的右结合性:
    右结合性:a > b ? a : i > j ? i : j 相当于 a > b ? a : ( i > j ? i : j )
     
    运算符优先级:
    括号 > 自增自减 > ~ ! > 算数运算符 > 位移运算 > 关系运算 > 逻辑运算 > 条件运算 > 赋值运算
     
    System.out.println(1+2+”java”+3+4);//3java34
    比较字符串是否相等必须使用equals方法!不能使用== "1".equals(cmd) 比cmd.equals("1") 要好。
                  
              
               

                     

    Java编译器不允许类型不同变量间的赋,除外明确指定强制类型转换。eg:不能将int类型赋值给byte,即使不会发生溢出。
     
     
    ===============================》    Java对象相关的理解:
    1、Java对象存放在可回收垃圾的堆中:
                 
    2、对象引用的概念:
    Dog myDog = new Dog();    //变量myDog只是指向一个临时对象的引用,myDog所占空间并不是对象的实际空间.
    引用变量的大小,与虚拟机JVM的实现有关。对于任意一个JVM来说,所有的引用大小都一样,但不同虚拟机间的引用大小可能不同。
    Java中的引用变量不能像C那样参与+-等运算。
    对象引用可以指向null,但这会导致引用之前指向的对象无法获取,最终因引用计数为0而被垃圾回收器GC收集。
    数组类型是一种对象。(可以测试下不同数量的数组名的size,验证数组不是对象引用;测试下Dog[] pets,数组pets的元素是对象引用,比较不同对象数组元素的size)
    eg: 
    1 Books[] myBooks = new Books[3];
    2 myBooks[0] = new Books();    //注意这句不能少,上面只是创建myBooks对象,但并没有为每个元素创建对象(开辟空间).
    3 myBooks[1] = new Books();
    4 myBooks[2] = new Books();
    5 myBooks[0].title = "Hello";
     
    包导入:
     
    类的成员变量是会默认初始化的,但所有的局部变量(包括普通方法、成员方法、代码块中定义的变量)均不会默认初始化,在使用局部变量前必须手动初始化否则会报错。
    static 修饰的成员变量是类变量,即所有的对象实例均可访问和修改,在类对象实例间共享;局部变量和局部内部类是不允许有访问修饰符和static修饰的。
    一个类定义了构造方法,系统就不会为其定义默认构造方法(此时需要手动定义默认构造函数即参数列表为空的构造函数,或在子类构造函数开头显示调用父类的有参构造函数);若此时在其子类的构造函数中没有显式调用父类定义的构造函数,将编译出错。若父类没有重载构造函数,子类的构造函数会自动调用父类的默认构造函数.
    如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。
    子类的所有构造方法内部, 第一行会(隐式)自动先调用父类的无参构造函数super();
    如果子类构造方法第一行显式调用了父类构造方法,系统就不再调用无参的super()了。
     
    一个源文件中包含多个类:
                 
     
    类、变量、函数的访问权限:(注意private不能用于修饰外部类和接口,因为接口需要继承)
     

    同一个类

    同一个包

    不同包的子类

    不同包非子类

    private

    *

    默认(friendly)

    *

    *

    protected

    *

    *

    *

    public

    *

    *

    *

    *

     
    注:
    使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public。
    protected 可以修饰数据成员、构造方法、方法成员,不能修饰类(内部类除外)。接口及接口的成员变量和成员方法不能声明为 protected。
    但是位于与父类不同包中的一个子类,能够使用其父类中protected成员的途径只能是,使用子类(或者是子类的子类)的引用。子类和父类在同一个包中则没有这个限制。这样就保证了其他包中的类只能访问它们所继承的部分成员。即在同一个包中,子类可以通过父类的引用来使用父类的protected变量/方法。
     
    非访问修饰符:为了实现一些其他的功能,Java 也提供了许多非访问修饰符。
    static 修饰符,用来修饰类方法和类变量。
    final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
    abstract 修饰符,用来创建抽象类和抽象方法。
    synchronized 和 volatile 修饰符,主要用于线程的编程。
    注:类中的 final 方法可以被子类继承,但是不能被子类修改。声明 final 方法的主要目的是防止该方法的内容被修改。
     
    抽象类:
    抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。
    一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。
    抽象类可以包含抽象方法和非抽象方法。
    抽象方法不能被声明成 final 和 static。
    任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。
    如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法
     
    synchronized 修饰符
    synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。
    transient 修饰符
    序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。
    该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型。
    当对象被序列化时(写入字节序列到目标文件)时,transient阻止实例中那些用此关键字声明的变量持久化;当对象被反序列化时(从源文件读取字节序列进行重构),这样的实例变量值不会被持久化和恢复。
     1 import java.io.FileInputStream;
     2 import java.io.FileNotFoundException;
     3 import java.io.FileOutputStream;
     4 import java.io.IOException;
     5 import java.io.ObjectInputStream;
     6 import java.io.ObjectOutputStream;
     7 import java.io.Serializable;
     8  
     9 //定义一个需要序列化的类
    10 class People implements Serializable{
    11     String name; //姓名
    12     transient Integer age; //年龄
    13     public People(String name,int age){
    14         this.name = name;
    15         this.age = age;
    16     }
    17     public String toString(){
    18         return "姓名 = "+name+" ,年龄 = "+age;
    19     }
    20  
    21 }
    22  
    23 public class TransientPeople {
    24     public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
    25         People a = new People("李雷",30);
    26         System.out.println(a); //打印对象的值
    27         ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("d://people.txt"));
    28         os.writeObject(a);//写入文件(序列化)
    29         os.close();
    30         ObjectInputStream is = new ObjectInputStream(new FileInputStream("d://people.txt"));
    31         a = (People)is.readObject();//将文件数据转换为对象(反序列化)
    32         System.out.println(a); // 年龄 数据未定义
    33         is.close();
    34     }
    35 }
    运行结果如下:
    姓名 = 李雷 ,年龄 = 30
    姓名 = 李雷 ,年龄 = null
    volatile 修饰符
    volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。一个 volatile 对象引用可能是 null。
     1 public class MyRunnable implements Runnable
     2 {
     3     private volatile boolean active;
     4     public void run()
     5     {
     6         active = true;
     7         while (active) // 第一行
     8         {
     9             // 代码
    10         }
    11     }
    12     public void stop()
    13     {
    14         active = false; // 第二行
    15     }
    16 }
    通常情况下,在一个线程调用 run() 方法(在 Runnable 开启的线程),在另一个线程调用 stop() 方法。 如果 第一行 中缓冲区的 active 值被使用,那么在 第二行 的 active 值为 false 时循环不会停止。
    但是以上代码中我们使用了 volatile 修饰 active,所以该循环会停止。
     
    final以及final static修饰的变量的初始化方式:https://www.runoob.com/java/java-modifier-types.html
    final 的作用随着所修饰的类型而不同:
    1、final 修饰类中的属性或者变量
    无论属性是基本类型还是引用类型,final 所起的作用都是变量里面存放的"值"不能变。
    这个值,对于基本类型来说,变量里面放的就是实实在在的值,如 1,"abc" 等。
    而引用类型变量里面放的是个地址,所以用 final 修饰引用类型变量指的是它里面的地址不能变,并不是说这个地址所指向的对象或数组的内容不可以变,这个一定要注意。
        例如:类中有一个属性是 final Person p=new Person("name"); 那么你不能对 p 进行重新赋值,但是可以改变 p 里面属性的值 p.setName('newName');
        final 修饰属性,声明变量时可以不赋值,而且一旦赋值就不能被修改了。对 final 属性可以在三个地方赋值:声明时、初始化块中、构造方法中,总之一定要赋值。
    2、final修饰类中的方法
    作用:可以被继承,但继承后不能被重写。
    3、final修饰类
    作用:类不可以被继承。
     
     
     
    成员变量和类变量的区别:https://www.runoob.com/java/java-object-classes.html
     
    package 的作用就是 c++ 的 namespace 的作用,防止名字相同的类产生冲突。Java 编译器在编译时,直接根据 package 指定的信息直接将生成的 class 文件生成到对应目录下。如 package aaa.bbb.ccc 编译器就将该 .java 文件下的各个类生成到 ./aaa/bbb/ccc/ 这个目录。
    import 是为了简化使用 package 之后的实例化的代码。假设 ./aaa/bbb/ccc/ 下的 A 类,假如没有 import,实例化A类为:new aaa.bbb.ccc.A(),使用 import aaa.bbb.ccc.A 后,就可以直接使用 new A() 了,也就是编译器匹配并扩展了 aaa.bbb.ccc. 这串字符串。
     
    为什么JAVA文件中只能含有一个Public类?
    java 程序是从一个 public 类的 main 函数开始执行的,(其实是main线程),就像 C 程序 是从 main() 函数开始执行一样。 只能有一个 public 类是为了给类装载器提供方便。 一个 public 类只能定义在以它的类名为文件名的文件中。
    每个编译单元(文件)都只有一个 public 类。因为每个编译单元都只能有一个公共接口,用 public 类来表现。该接口可以按照要求包含众多的支持包访问权限的类。如果有一个以上的 public 类,编译器就会报错。 并且 public类的名称必须与文件名相同(严格区分大小写)。 当然一个编译单元内也可以没有 public 类。
     
    Java中常量用final修饰. Java中各种类型所占字节数固定。局部变量是在栈中存放,常量和静态变量是在内存静态存储区域存放,对象(包括成员变量)均是在堆中存放。静态方法只能访问静态变量,因为静态方位独立于对象,对象创建前已有静态方法。静态变量是可以改变的,但一般将静态变量以public static final  type varname的形式定义成常量.
     
    Java中其他类型和字符串类型的相互转换:https://www.runoob.com/java/java-basic-datatypes.html
    Java允许隐式自动类型转换(低范围到大范围);但大范围类型到小范围类型必须显式强制类型转换。
    原始类型:boolean,char,byte,short,int,long,float,double。
    包装类型:Boolean,Character,Byte,Short,Integer,Long,Float,Double。
    所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类 Number 的子类。
    这种由编译器特别支持的包装称为装箱,所以当内置数据类型被当作对象使用的时候,编译器会把内置类型装箱为包装类。相似的,编译器也可以把一个对象拆箱为内置类型。Number 类属于 java.lang 包。
            int arr = new Integer(10);
            Integer arr1 = arr;
    String类型是不可改变的常量(即不可改变某个字符),所有的String修改方法均会返回一个新的String对象,源对象不会变。
    1 public final class String
    2     implements java.io.Serializable, Comparable<String>, CharSequence {
    3     /** The value is used for character storage. */
    4     private final char value[];
    5 }
    字符串实际上就是一个 char 数组,并且内部就是封装了一个 char 数组。并且这里 char 数组是被 final 修饰的。并且 String 中的所有的方法,都是对于 char 数组的改变,只要是对它的改变,方法内部都是返回一个新的 String 实例。
    1 String s = "Google";
    2 System.out.println("s = " + s);
    3 s = "Runoob";
    4 System.out.println("s = " + s);
    输出结果为:
    Google
    Runoob
    从结果上看是改变了,但为什么门说String对象是不可变的呢?
    原因在于实例中的 s 只是一个 String 对象的引用,并不是对象本身,当执行 s = "Runoob"; 创建了一个新的对象 "Runoob",而原来的 "Google" 还存在于内存中。
     
    String a = "a";
    String b = "b";
    String c = a + b;
    相当于:
            String c = new StringBuffer().append(a).append(b).toString();
    对于字符串的加运算,当编译成 class 文件时,会自动编译为 StringBuffer 来进行字符串的连接操作。
    同时对于字符串常量池:当一个字符串是一个字面量时,它会被放到一个常量池中,等待复用。
    1 String a = "saff";
    2 String b = "saff";
    3 String c = new String("saff");
    4 System.out.println(a.equal(b)); // true
    5 System.out.println(a.equal(c)); // true
    这个就是字符串的常量池。
    面试题二:
    1 String s1="a"+"b"+"c";
    2 String s2="abc";
    3 System.out.println(s1==s2);
    4 System.out.println(s1.equals(s2));
    5 java 中常量优化机制,编译时 s1 已经成为 abc 在常量池中查找创建,s2 不需要再创建。
    面试题三:
    1 String s1="ab";
    2 String s2="abc";
    3 String s3=s1+"c";
    4 System.out.println(s3==s2); // false
    5 System.out.println(s3.equals(s2)); // true
    先在常量池中创建 ab ,地址指向 s1, 再创建 abc ,指向 s2。对于 s3,先创建StringBuilder(或 StringBuffer)对象,通过 append 连接得到 abc ,再调用 toString() 转换得到的地址指向 s3。故 (s3==s2) 为 false
     
    Java:String、StringBuffer 和 StringBuilder 的区别:
    String:字符串常量,字符串长度不可变。Java中String 是immutable(不可变)的。用于存放字符的数组被声明为final的,因此只能赋值一次,不可再更改。
    StringBuffer:字符串变量(Synchronized,即线程安全)。如果要频繁对字符串内容进行修改,出于效率考虑最好使用 StringBuffer,如果想转成 String 类型,可以调用 StringBuffer 的 toString() 方法。Java.lang.StringBuffer 线程安全的可变字符序列。在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。
    StringBuilder:字符串变量(非线程安全)。在内部 StringBuilder 对象被当作是一个包含字符序列的变长数组。
    基本原则:
    如果要操作少量的数据用 String ;
    单线程操作大量数据用StringBuilder ;
    多线程操作大量数据,用StringBuffer。
    当对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类。
    和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。
    StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。
    由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。
    1 public class Test{
    2   public static void main(String args[]){
    3     StringBuffer sBuffer = new StringBuffer("菜鸟教程官网:");
    4     sBuffer.append("www");
    5     sBuffer.append(".runoob");
    6     sBuffer.append(".com");
    7     System.out.println(sBuffer);  
    8   }
    9 }
    对整数进行格式化:%[index$][标识][最小宽度]转换方式(1$表示第一个参数)
    对浮点数进行格式化:%[index$][标识][最少宽度][.精度]转换方式
     
    java中继承:只能继承一个类,但可以继承实现多个接口。
    继承时子类重载的变量/方法的修饰符访问权限应不低于父类对应的:
    父类中声明为 public 的方法在子类中也必须为 public。
    父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
    父类中声明为 private 的方法,不能够被继承。
    对于父类中定义为private的变量,子类不能直接继承或访问,需要通过在构造函数中super调用父类的有参构造函数才能继承。
    父子类对象的向上或向下转型:https://www.runoob.com/w3cnote/java-transformation-problem.html
    父类对象不允许转成子类对象,但子类对象可以自动转成父类对象;并且但父类对象的引用指向子类对象时,可以通过强制类型转换的方法将该引用转成子类对象。
    Java子类重写继承的方法时,不可以降低方法的访问权限,子类继承父类的访问修饰符要比父类的更大,也就是更加开放。
    假如父类是protected修饰的,其子类只能是protected或者是public,绝对不能是friendly(默认的访问范围)或者private,当然使用private就不是继承了。
    还要注意的是,继承当中子类抛出的异常必须是父类抛出的异常的子异常,或者子类抛出的异常要比父类抛出的异常要少。
    当执行重写方法时,运行时类型检查:
    1 public class TestDog{
    2    public static void main(String args[]){
    3       Animal a = new Animal(); // Animal 对象
    4       Animal b = new Dog(); // Dog 对象
    5       a.move();// 执行 Animal 类的方法
    6       b.move();//执行 Dog 类的方法
    7    }
    8 }
    注:父类申明变量指向子类实例,该父类变量不能调用父类不存在的变量和方法,否则会编译错误。
    虚函数概念:就是实现类对象的动态绑定,从而能调用子类自己重写的方法;Java中普通函数即是C++中的虚函数。详见:https://www.runoob.com/java/java-polymorphism.html
    多态的实现方式:重写、重载、接口、抽象类和抽象方法。详见:https://www.runoob.com/java/java-polymorphism.html
     
    在使用instanceof 判断对象类型时,子类对象是父类,但父类对象不是子类。并且在判断一个实例引用的类型时,使用的是实际类型,而不是声明的类型。
    1 Vehicle v2 = new Car(); // v2 是 Car 类型
    2 Vehicle v3 = new Vehicle();
    3 boolean result2 = v2 instanceof Car; // true
    4 boolean result3 = v2 instanceof Vehicle; // true
    5 boolean result4 = v3 instanceof Car; // false

    下表中具有最高优先级的运算符在的表的最上面,最低优先级的在表的底部。

    类别操作符关联性
    后缀 () [] . (点操作符) 左到右
    一元 + + - !〜 从右到左
    乘性  * /% 左到右
    加性  + - 左到右
    移位  >> >>>  <<  左到右
    关系  >> = << =  左到右
    相等  ==  != 左到右
    按位与 左到右
    按位异或 ^ 左到右
    按位或 | 左到右
    逻辑与 && 左到右
    逻辑或 | | 左到右
    条件 ?: 从右到左
    赋值 = + = - = * = / =%= >> = << =&= ^ = | = 从右到左
    逗号 左到右
     
     
    Java除了支持普通类似C语言形式的for(int i; i<10; i++)循环,还支持增强版的for循环:
    1 int [] numbers = {10, 20, 30, 40, 50};
    2 for(int x : numbers ) {        //需要注意的是int 不能提到外面去声明. 普通的for循环可以。
    3          // x 等于 30 时跳出循环
    4          if( x == 30 ) {
    5             break;
    6          }
    7 }
    跳出多层循环的方法:使用标识符+break
     1 public class Test {
     2     public static void main(String []args) {
     3         lable:
     4         for(int i = 0; i < 10; i++){
     5             for(int j = 0; j < 10; j++){
     6                 if(i * 10 + j > 29){
     7                     break lable;
     8                 }
     9                 System.out.print("" + i + j +" ");
    10             }
    11             System.out.println("
     -------------------------------------- 
    ");
    12         }
    13         System.out.println("输出完毕!");
    14     }
    15 }
    多维数组定义时,必须确定高维上的长度,低维上的数组长度可以不同:(和C语言中有点不一样)
    1 String s[][] = new String[2][];
    2 s[0] = new String[2];    
    3 s[1] = new String[3];
    4 s[0][0] = new String("Good");
    5 s[0][1] = new String("Luck");
    6 s[1][0] = new String("to");
    7 s[1][1] = new String("you");
    8 s[1][2] = new String("!");
    java.util.Arrays 类能方便地操作数组,它提供的所有方法都是静态的。即可以通过Arrays.sort(arr)的形式操作数组.
    1 public static int binarySearch(Object[] a, Object key)
    2 public static boolean equals(long[] a, long[] a2)
    3 public static void fill(int[] a, int val)
    4 public static void sort(Object[] a)
    switch 语句中的变量类型可以是: byte、short、int 或者 char。从 Java SE 7 开始,switch 支持字符串 String 类型了,同时 case 标签必须为字符串常量或字面量。
    case 语句中的值的数据类型必须与变量的数据类型相同,而且只能是常量或者字面常量。
    当变量的值与 case 语句的值相等时,那么 case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语句。default可以不要break.
     
    注意 == 与 equals的区别:
    == 它比较的是对象的地址
    equals 比较的是对象的内容
    eg:
     1 Integer i = new Integer(100);
     2 Integer j = new Integer(100);
     3 System.out.print(i == j); //false。因为 new 生成的是两个对象,其内存地址不同。
     4 eg:
     5 Integer a=123;
     6 Integer b=123;
     7 System.out.println(a==b); // 输出 true。Java 会对 -128 ~ 127 的整数进行缓存,所以当定义两个变量初始化值位于 -128 ~ 127 之间时,两个变量使用了同一地址
     8 eg:
     9 a=1230;
    10 b=1230;
    11 System.out.println(a==b); // 输出 false。当两个 Integer 变量的数值超出 -128 ~ 127 范围时, 变量使用了不同地址
    12 System.out.println(a.equals(b)); // 输出 true
     
    sleep()使当前线程进入停滞状态(阻塞当前线程),让出CPU的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会。
     
    函数的可变参数:
        typeName... parameterName
    在方法声明中,在指定参数类型后加一个省略号(...) 。一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
    1 void function(String... args);
    2 void function(String [] args);
    这两个方法的命名是相等的,不能作为方法的重载。可变参数,即可向函数传递 0 个或多个参数,如:
    1 void function("Wallen","John","Smith");
    2 void function(new String [] {"Wallen","John","Smith"});
    finalize() 方法:
    Java 允许定义这样的方法,它在对象被垃圾收集器析构(回收)之前调用,这个方法叫做 finalize( ),它用来清除回收对象。
    例如,你可以使用 finalize() 来确保一个对象打开的文件被关闭了。在 finalize() 方法里,你必须指定在对象销毁时候要执行的操作。
    finalize() 一般格式是:
    1 protected void finalize()
    2 {
    3    // 在这里终结代码
    4 }
    关键字 protected 是一个限定符,它确保 finalize() 方法不会被该类以外的代码调用。当然,Java 的内存回收可以由 JVM 来自动完成。如果你手动使用,则可以使用上面的方法。
     
    利用Scanner类从输入流中读取数字:https://www.runoob.com/java/java-scanner-class.html
    利用BufferedReader类从输入流中读取字符/字符串:https://www.runoob.com/java/java-files-io.html
    Scanner和BufferedReader的区别:
    BufferedReader 是支持同步的,而 Scanner 不支持。如果我们处理多线程程序,BufferedReader 应当使用。
    BufferedReader 相对于 Scanner 有足够大的缓冲区内存。
    Scanner 有很少的缓冲区(1KB 字符缓冲)相对于 BufferedReader(8KB字节缓冲),但是这是绰绰有余的。
    BufferedReader 相对于 Scanner 来说要快一点,因为 Scanner 对输入数据进行类解析,而 BufferedReader 只是简单地读取字符序列。
    文件的读写、目录的操作:https://www.runoob.com/java/java-files-io.html
     
     
    运行时异常(非检查异常)和检查异常:https://blog.csdn.net/tanga842428/article/details/52751303
    1、检查性异常: 不处理编译不能通过
    2、非检查性异常:不处理编译可以通过,如果有抛出直接抛到控制台
    3、运行时异常: 就是非检查性异常
    4、非运行时异常: 就是检查性异常
    异常发生在程序运行时,语法错误在程序编译阶段会被检查。
                                    
    1.检查型异常(Checked Exception)
    个人理解:所谓检查(Checked)是指编译器要检查这类异常,检查的目的一方面是因为该类异常的发生难以避免,另一方面就是让开发者去解决掉这类异常,所以称为必须处理(try ...catch)的异常。如果不处理这类异常,集成开发环境中的编译器一般会给出错误提示。
    例如:一个读取文件的方法代码逻辑没有错误,但程序运行时可能会因为文件找不到而抛出FileNotFoundException,如果不处理这些异常,程序将来肯定会出错。所以编译器会提示你要去捕获并处理这种可能发生的异常,不处理就不能通过编译。
                    
     
    2.非检查型异常(Unchecked Exception)
    个人理解:所谓非检查(Unchecked)是指编译器不会检查这类异常,不检查的则开发者在代码的编辑编译阶段就不是必须处理,这类异常一般可以避免,因此无需处理(try ...catch)。如果不处理这类异常,集成开发环境中的编译器也不会给出错误提示。
    例如:你的程序逻辑本身有问题,比如数组越界、访问null对象,这种错误你自己是可以避免的。编译器不会强制你检查这种异常。
                    
    异常处理时,即使try语句块中有return语句,finally语句块仍然会执行,除非try语句块中有System.exit(0);
    并且finally语句块中不应该有return语句,这样会导致try语句块或catch语句块中抛出的异常被忽略。
    finally块的语句在try或catch中的return语句执行之后返回之前执行且finally里的修改语句可能影响也可能不影响try或catch中 return已经确定的返回值,
    若finally里也有return语句则覆盖try或catch中的return语句直接返回;若没有return 语句则finally对返回值的修改,并不会影响前面return的值。
     
    Java抽象类不允许实例化(编译不通过),但抽象类允许有方法实现,有抽象方法的类必须是抽象类。定义抽象类或抽象方法在public后加上abstract即可。类方法不能定义成抽象方法(即static和abstract不能一起用)
    子类在重写父类的方法时,最好在方法头前加上@Override
    接口只能包含抽象方法,不能有实现。
    类继承使用extends,实现接口使用implements。
    可以用抽象类或接口声明一个变量(绑定在一个实现抽象类或接口的对象),但不能实例化一个抽象类或接口对象。除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。
    接口没有构造方法。接口中所有的方法必须是抽象方法。接口不能包含成员变量,除了 static 和 final 变量。
     
     
    Java集合框架:https://www.runoob.com/java/java-collections.html(遍历集合的几种方式)
    任何对象加入集合类后,自动转变为Object类型,所以在取出的时候,需要进行强制类型转换。 
    任何对象没有使用泛型之前会自动转换Object类型,使用泛型之后不用强制转换。
     

    ====================    遍历 ArrayList
     1 public class Test{
     2  public static void main(String[] args) {
     3      List<String> list=new ArrayList<String>();
     4      list.add("Hello");
     5      list.add("World");
     6      list.add("HAHAHAHA");
     7      //第一种遍历方法使用 For-Each 遍历 List
     8      for (String str : list) { //也可以改写 for(int i=0;i<list.size();i++) 这种形式
     9         System.out.println(str);
    10      }
    11  
    12      //第二种遍历,把链表变为数组相关的内容进行遍历
    13      String[] strArray=new String[list.size()];
    14      list.toArray(strArray);
    15      for(int i=0;i<strArray.length;i++) //这里也可以改写为 for(String str:strArray) 这种形式
    16      {
    17         System.out.println(strArray[i]);
    18      }
    19      
    20     //第三种遍历 使用迭代器进行相关遍历
    21      Iterator<String> ite=list.iterator();
    22      while(ite.hasNext())//判断下一个元素之后有值
    23      {
    24          System.out.println(ite.next());
    25      }
    26  }
    27 }
    =============================    遍历 Map
     1 public class Test{
     2      public static void main(String[] args) {
     3       Map<String, String> map = new HashMap<String, String>();
     4       map.put("1", "value1");
     5       map.put("2", "value2");
     6       map.put("3", "value3");
     7       
     8       //第一种:普遍使用,二次取值
     9       System.out.println("通过Map.keySet遍历key和value:");
    10       for (String key : map.keySet()) {    //若不是泛型定义map,此句会编译不通过key是object类型需要强转
    11        System.out.println("key= "+ key + " and value= " + map.get(key));
    12       }
    13       
    14       //第二种
    15       System.out.println("通过Map.entrySet使用iterator遍历key和value:");
    16       Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
    17       while (it.hasNext()) {
    18        Map.Entry<String, String> entry = it.next();
    19        System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
    20       }
    21       
    22       //第三种:推荐,尤其是容量大时
    23       System.out.println("通过Map.entrySet遍历key和value");
    24       for (Map.Entry<String, String> entry : map.entrySet()) {
    25        System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
    26       }
    27     
    28       //第四种
    29       System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
    30       for (String v : map.values()) {
    31        System.out.println("value= " + v);
    32       }
    33      }
    34 }
    泛型的概念:
    eg:public static <T extends Comparable<T>> T maximum(T x, T y, T z){}        //函数的返回类型和参数类型均为T
    <T extends Comparable<T>>:表示类型T,extends表示继承,Comparable<T>表示泛型接口Comparable能比较T类型的变量。因此这里定义的类型T必须是实现了Comparable接口的类型,并且接口的参数是T的实例。
    <T extends Comparable<? super T>>:表示类型 T 必须实现 Comparable 接口,并且这个接口的类型是 T 或 T 的任一父类。这样声明后,T 的实例之间,T 的实例和它的父类的实例之间,可以相互比较大小。例如,在实际调用时若使用的具体类是 Dog (假设 Dog 有一个父类 Animal),Dog 可以从 Animal 那里继承 Comparable<Animal> ,或者自己 implements Comparable<Dog> 。
    注:?表示类型通配符,用于代替具体的类型参数,这里即T的任意父类或T本身。
    因此有称extends表示类型上界,super表示类型下界,这种泛型参数称为有界泛型参数。泛型参数必须是引用类型,不能是原始类型(eg:int、float、char等)但可以是他们的包装类
    接口Comparable声明了compareTo方法,返回int类型,负数表示<,0表示=,正数表示>
    =============    泛型类的定义
     1 public class Box<T> {
     2   private T t;
     3   public void add(T t) {
     4     this.t = t;
     5   }
     6  
     7   public T get() {
     8     return t;
     9   }
    10  
    11   public static void main(String[] args) {
    12     Box<Integer> integerBox = new Box<Integer>();
    13     Box<String> stringBox = new Box<String>();
    14  
    15     integerBox.add(new Integer(10));
    16     stringBox.add(new String("菜鸟教程"));
    17  
    18     System.out.printf("整型值为 :%d
    
    ", integerBox.get());
    19     System.out.printf("字符串为 :%s
    ", stringBox.get());
    20   }
    21 }
    ============    泛型通配符
    1 public static void getUperNumber(List<? extends Number> data) {    //表示Number的任意子类
    2           System.out.println("data :" + data.get(0));
    3        }
    <? extends T>表示该通配符所代表的类型是T类型的子类。
    <? super T>表示该通配符所代表的类型是T类型的父类。
     
    =============    泛型只在编译时进行类型检查
     1 import java.util.*;
     2 public class Main
     3 {
     4     public static void main(String[] args)
     5     {
     6         List<Integer> list = new ArrayList<>();
     7         list.add(12);
     8 //        list.add("a");    //这里直接添加会报错
     9         Class<? extends List> clazz = list.getClass();
    10         try{
    11             Method add = clazz.getDeclaredMethod("add", Object.class);
    12             add.invoke(list, "kl");     //但是通过反射添加,是可以的
    13         }
    14         catch (Exception e){
    15         }
    16         System.out.println(list);
    17     }
    18 }
     
    readOject反序列化方法返回的是object类型,需要转成合适类型的引用。
    一个类的对象要想序列化成功,必须满足两个条件:
                该类必须实现 java.io.Serializable 对象。
                该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。
    通常情况下,用transient和static修饰的变量是不能被序列化的,但是通过在序列化的类中写writeObject(ObjectOutputStream stream)和readObject(ObjectInputStream stream)方法,可以实现序列化。 
    有人说static的变量为什么不能序列化,因为static的变量可能被改变。 
    static final的常量可以被序列化。 
     
    java多线程能提高CPU的利用效率体现在:
    磁盘IO是比较耗时的操作,且与CPU计算是相互独立的,而CPU计算时间往往较短;因此可以在某个线程在读写IO时,利用CPU来跑另一个线程的计算。
    守护线程是服务于用户线程的, 当所有用户线程执行完时,守护线程即使未执行完也会随着JVM的推出而终止.
     
    java常用功能函数的使用:https://www.runoob.com/java/java-examples.html
     
    java 正则表达式区分大小写:https://www.cnblogs.com/cRaZy-TyKeIo/p/3454458.html
     
    java中Object转String(避免null导致的空指针异常):https://www.cnblogs.com/wuxiang12580/p/10370127.html
     
     
    synchronized 详解:

    1、对于静态方法,由于此时对象还未生成,所以只能采用类锁;

    2、只要采用类锁,就会拦截所有线程,只能让一个线程访问。

    3、对于对象锁(this),如果是同一个实例,就会按顺序访问,但是如果是不同实例,就可以同时访问。

    4、如果对象锁跟访问的对象没有关系,那么就会都同时访问。

     
    ExecutorService与线程池ThreadPoolExecutor:
     
    线程池--拒绝策略RejectedExecutionHandler:
     
    线程局部变量ThreadLocal:
    ThreadLocal提供了线程的局部变量,每个线程都可以通过set()get()来对这个局部变量进行操作,但不会和其他线程的局部变量进行冲突,实现了线程的数据隔离。
    往ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。
    ThreadLocal设计的目的就是为了能够在当前线程中有属于自己的变量,并不是为了解决并发或者共享变量的问题。
     
    java并发编程:
     
    接口的默认修饰符:
    Java的interface中,成员变量的默认修饰符为:public static final  
    public static final String name = "张三";  等价于  String name = "张三";
    方法的默认修饰符是:public abstract
    public abstract List<String> getUserNames(Long companyId);  等价于  List<String> getUserNames(Long companyId);
    接口只是对一类事物属性和行为的更高次抽象;对修改关闭,对扩展开放,可以说是java中开闭原则的一种体现吧。
  • 相关阅读:
    pip install selenium==版本号 报错
    解决phantomjs输出中文乱码
    phantomjs学习之网页访问测速
    phantomjs学习之截图
    bzoj1069-最大土地面积
    hdu4372-Count the Buildings
    bzoj3786-星系探索
    Codeforces633H-Fibonacci-ish II
    hdu3625-Rooms
    斯特林数
  • 原文地址:https://www.cnblogs.com/luckyboylch/p/12327145.html
Copyright © 2011-2022 走看看