基础知识

编译:javac MyFirst.java
运行:java MyFirst
在指定目录下执行java编译clas文件:https://www.runoob.com/java/env-classpath.html
eg:java -classpath C:\java\DemoClasses 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("\n -------------------------------------- \n");
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\n\n", integerBox.get());
19     System.out.printf("字符串为 :%s\n", 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中开闭原则的一种体现吧。
posted @ 2020-02-18 17:29  Coding练习生  阅读(542)  评论(0编辑  收藏  举报