Skip to the content.

第一部分 入门

开发环境

Java虚拟机

JRE&JDK

入门程序

程序开发步骤说明

第四章 常量

变量&数据类型

数据类型

基本数据类型

Java 中默认类型:整型是 int,浮点类型是 double 想要精确的数字不推荐用 double,用 BigDemical。

引用数据类型

字符串,数组,类,接口,Lambda

注意事项:

变量

强制数据类型转换

byte num1 = 40;
byte num2 = 50;
//byte + byte --> int + int
int result = num1 + num2;
//如果用 byte接收 需要强转
byte result = (byte)(num1 + num2);
// short 同理

ASCII码表

0 -- 48
A -- 65
a -- 97

数字和字符的对照关系表(编码表)

ASCII 码表:American Standard Code for Information Interchange

Unicode 码表:万国码。也是数字和符号对照关系,开头 0-127 部分和 ASCII 完全一样,但是从 128 开始包含更多字符。

易错点

byte short char 这些在计算的时候,会有类型提升,提升为 int 进行计算。

public static void main(String[] args) {
    byte a = 8;
    byte b = 127;
    b = a+b; 
    // 会报错,提示你要进行强制类型转换。因为计算的时候,a和b会被提升为int类型,然后再进行计算,得到的结果也是int的,要把int类型的赋值给byte类型的变量需要进行强制类型转换。
}

包装类型的比较

public class Demo {
    public static void main(String[] args) {
        Integer b = new Integer(47);
        Integer a = new Integer(47);
        System.out.println(a == b);  // false 因为 a b 是不同的对象。
        Integer c = Integer.valueOf(47);
        Integer d = Integer.valueOf(47);
        System.out.println(c == d); // true 因为 valueOf 创建对象是会先从 IntegerCache 缓存中找,有就返回缓存中的对象。
        							// IntegerCache 是静态内部类。静态内部类在你使用的时候才会进行加载。注意:是说的静态内部类。
    }
}

静态内部类加载时机的测试。遇到 new、getstatic、putstatic 或 invokestatic 这四条字节码指令执行的时候,如果类没有进行过初始化,则需要先触发其初始化。

public class Demo {
    // VM参数 -XX:+TraceClassLoading
    public static void main(String[] args) {
        int a = 0x2f;
        // 调用静态内部类,控制台输出,它被加载了。不用静态内部类,它就不加载。
        System.out.printf("", TestClassLoading.d); 
    }

    static class TestClassLoading {
        static int d = 10;
        { System.out.println("d"); }
    }
}

常用运算

基本语法

switch & 循环

switch

基本语法

public class Demo {
    public static void main(String[] args) {
        int a = 5;
        switch (a) {
            case 1:
                System.out.println(1);
            case 2:
                System.out.println(2);
            default:
                System.out.println("over!");
        }
    }
}

Java 7 之前想用 String 判断的话

package tij.chapter5;

public class StringSwitch {
    public static void main(String[] args) {
        String color = "red";
        // 老的方式: 使用 if-then 判断
        if ("red".equals(color)) {
            System.out.println("RED");
        } else if ("green".equals(color)) {
            System.out.println("GREEN");
        } else if ("blue".equals(color)) {
            System.out.println("BLUE");
        } else if ("yellow".equals(color)) {
            System.out.println("YELLOW");
        } else {
            System.out.println("Unknown");
        }
        // 新的方法: 字符串搭配 switch
        switch (color) {
            case "red":
                System.out.println("RED");
                break;
            case "green":
                System.out.println("GREEN");
                break;
            case "blue":
                System.out.println("BLUE");
                break;
            case "yellow":
                System.out.println("YELLOW");
                break;
            default:
                System.out.println("Unknown");
                break;
        }
    }
}

switch 中可以用 String 的原理

调用字符串的 hashCode 方法,switch 中先比较 hashCode 的值,hashCode 的值一致再比较字符串的值。

public class TestSwitch {
    public static void main(String[] args) {
        String str = "dd";
        switch (str) {
            case "dd":
                System.out.println("odk");
                break;
            case "cc":
            default:
                System.out.println("over!");
        }
    }
}
// 反编译后的代码
public class TestSwitch {
    public TestSwitch() {}

    public static void main(String[] args) {
        String str = "dd";
        byte var3 = -1;
        switch(str.hashCode()) {
            case 3168:
                if (str.equals("cc")) { var3 = 1; }
                break;
            case 3200:
                if (str.equals("dd")) { var3 = 0; }
        }

        switch(var3) {
            case 0:
                System.out.println("odk");
                break;
            case 1:
            default:
                System.out.println("over!");
        }
    }
}

循环

for 循环,最常用的迭代形式

for(  ;  ;  ){
    
}

for(初始化表达1 ; 布尔表达式2 ; 步进表达式4){
    循环体3
}
流程 1 2 3 4 --> 2 3 4 --> 2 3 4 -->直到2不满足为止
初始化语句只会执行一次

逗号操作符:在 for 循环的初始化和步进控制中定义多个变量。

public class CommaOperator {
    public static void main(String[] args) {
        for(int i = 1, j = i + 10; i < 5; i++, j = i * 2) {
        	System.out.println("i = " + i + " j = " + j);
        }
    }
}

增强 for 循环 foreach:操纵数组和集合

for(float x : f){
    System.out.println(x);
}
// 将每一个f的元素赋值给x

do-while

do {
    // doing something
} while (condtion);

break & continue

break 跳出一层循环,continue 开启下一次循环。IDEA 点击关键字可以看到下一步会执行到那里。

goto

 public class GoToDemo {
     public static void main(String[] args) {
         outer:
         for (int i = 0; i < 10; i++) {
             for (int j = 0; j < 10; j++) {
                 if (j == 5) {
                     System.out.println(j);
                     break outer;
                 }
             }
         }
     }
 }

重载与重写

方法调用的三种格式

1.单独调用:方法名称(参数) 2.打印调用:System.out.println(方法名称(参数)) 3.赋值调用:数据类型 变量名称 = 方法名称(参数)

方法重载 Overload

// 以下参数顺序不一样也是重载!
public static void test(int a, short b){}
public static void test(short b,int a){}

重载的注意事项

public static void f1(short i){
    System.out.println("f1(short)");
}
public static void f1(byte i){
    System.out.println("f1(byte)");
}
public static void f1(int i){
    System.out.println("f1(int)");
}
public static void main(String[] args) {
    short i = 5;
    byte ii = 6;
    int iii = 7;
    f1(1);  // f1(int)
    f1(1);	// f1(int)
    f1(1);	// f1(int)
    System.out.println("==========华丽的分割线==========");
    f1(i);	// f1(short)
    f1(ii);	// f1(byte)
    f1(iii);// f1(int)
}

数组

数组的初始化

int [] array = new int[300];
int [] array = new int[]{1,2,3,4,5,6}; // 标准格式
int [] array = {1,2,3,4,5,6}; // 省略格式
// 静态初始化不能拆分成
int [] array;
array = {1,2,34};
// 这样是错误得

动态初始化有默认值的过程, 整型 默认为 0 浮点 默认为 0.0 字符 默认为 ‘\u0000’ 布尔 默认为 false 引用 默认为 null

静态初始化也有,不过系统自动马上将默认值替换为了大括号当中的具体数值。

数组作为参数,返回值

public static void cals(int[] arr){
    xxxx
}

public static int[] calculate(int a,int b){
    int [] array = {a,b};
    return array;
}

数组作为参数,作为返回值其实都是数组的地址值

Java 内存划分

Java 的垃圾回收,对于提高对象的创建速度,具有明显的效果。Java 从堆空间分配空间的速度,可以和其他语言从堆栈上分配空间的速度相媲美。在某些 Java VM 中,堆的实现截然不同,但是堆内存的分配可以看做:有一个堆指针,简单移动到尚未分配的区域,通过这种方式分配对象内存,其效率比得上 C++ 在栈上分配空间的效率。当然,在实际工作方面,还有少量额外的开销,但是比不上查找可用空间的开销。(Java GC 会清理出可用的空间,堆指针在空间中移动,这样就完成了内存的分配。而 C++ 需要遍历查找可用的内存,这个查找开销较大。这样一对比,会发现,Java 分配对象的速度并不比 C++ 慢

Java 的 GC 工作的时候,一面回收内存空间,一面使堆中的对象紧凑排列。

Java 的优化技术==>JIT(Just-In-Time):这种技术可以把程序的全部或部分代码翻译成本地机器码,提升程序速度。当要装载某个类时,编译器会先找到其 .class 文件,然后将该类的字节码转入内存。此时有两种方式可供选择

常见异常

ArrayIndexOfBoundsException

NullPointException

OutOfMemmory

OOP

类&对象

定义类的格式

修饰符 class 类名{
	//1.成员变量(Field 描述类和对象的属性信息)

	//2.成员方法(Method:描述类或者对象的行为信息)

	//3.构造器(Constructor:初始化一个类的对象并返回引用)

	//4.代码块

	//5.内部类
}

构造器

this 关键字的作用

封装

封装的作用

封装的规范

小结:封装的核心思想==>合理隐藏,合理暴露。

static 关键字

Java 通过成员变量是否有 static 修饰来区分是属于类的还是属于对象的。

static ==> 静态 ==> 修饰的成员(方法和成员变量)属于类本身。

成员方法也类似:

static 修饰,属于类本身,随类的加载而加载,因为只有一份,所以可以被类和类的对象共享。

类与类之间的关系

对象的内存图

成员变量和局部变量

public class Demo01VariableDifference {
 
    String name; // 成员变量

    public void methodA() {
        int num = 20; // 局部变量
        System.out.println(num);
        System.out.println(name);
    }

    public void methodB(int param) { // 方法的参数就是局部变量
        // 参数在方法调用的时候,必然会被赋值的。
        System.out.println(param);

        int age; // 局部变量
        System.out.println(age); // 没赋值不能用

        System.out.println(num); // 错误写法!
        System.out.println(name);
    }
}

变量的初始化顺序

public Class Counter{
    int i;
    public Counter(){
        i=7;
        //在调用构造方法为 i 赋值为 7之前,i 就已经被初始化为 0 了。
        // 即,自动初始化发生在构造器被调用之前。
    }
}
/**
PS:回顾下类加载过程
- 加载(将字节码文件加载进内存)
- 验证(验证 Class 文件是否符合 JVM 规范,并确保它们不会危害虚拟机安全)
- 准备(为静态变量分配内存并设置类变量的初始值)
- 解析(将常量池内的符号引用替换为直接引用)
- 初始化(执行 clinit 方法),初始化指的是代码中定义的初始化,而非编译器默认的初始化
类加载是类加载,创建实例化对象是创建对象。
*/