以下图片来自均来源于网络,侵删
首先三者之间存在包含关系
JVM + 核心类库 = JRE
JRE + java开发工具(javac.exe/jar.exe) = JDK
Java Virtual Machine(Java虚拟机)
它是整个java实现跨平台的最核心的部分。所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行。也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。 JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
那么只有JVM还能不能让class的执行?
不能,因为在解释class的时候JVM需要调用解释所需要的类库lib,而jre包含lib类库。
Java runtime environment(Java运行环境)
JRE是运行基于Java语言编写的程序所不可缺少的运行环境。
JRE中包含了Java virtual machine(JVM),runtime class libraries和Java application launcher。这些是运行Java程序的必要组件。与大家熟知的JDK不同,JRE是Java运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器),只是针对于使用Java程序的用户
Java Development Kit (Java开发工具包)
JDK是Sun Microsystems公司针对Java开发员的产品。
JDK中包含JRE,在JDK的安装目录下有一个名为jre的目录,里面有两个文件夹bin和lib,在这里 可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib和起来就称为jre。
JDK是整个JAVA的核心,包括了Java运行环境JRE(Java Runtime Envirnment)、一堆Java工具(javac/java/jdb等)和Java基础的类库(即Java API 包括rt.jar)。
其中整型 (4种)、字符型 (1种)、浮点型 (2种)、布尔型(1种)
类型 | 缺省值 | 长度(bit) | 范围 |
---|---|---|---|
byte [字节] | 0 | 8 | -27 ~ 27-1 |
short [短整数] | 0 | 16 | -215 ~ 215-1 |
int [整数] | 0 | 32 | -231 ~ 231-1 |
long [长整数] | 0 | 64 | -263 ~ 263-1 |
float单精度浮点数] | 0.0 | 32 | -2128 ~ 2127 |
float单精度浮点数] | 0.0 | 64 | -21024 ~ 21023 |
char[字符型] | 空 | 16 | 0 ~ 216-1 |
boolean[布尔] | false | 1 | false、true |
这些基本类型都有对应的包装类
byte(Byte)、short(Short)、int(Integer)、long(Long)、float(Float)、double(Double)、char(
Character)、boolean(Boolean)
既然这些基本类型对应包装类都是类,所以他们的默认值全是null
2.1 类型转换
不同类型之间的数据可以互相转换,但是要满足一定的规则:
精度高的数据类型就像容量大的杯子,可以放更大的数据
精度低的数据类型就像容量小的杯子,只能放更小的数据
需要注意的两点是:
虽然short和char都是16位的,长度是一样的但是彼此之间依然需要进行强制转换
boolean类型不能与其他类型相互转换
//低精度向高精度转换
long l = 5L;
int i = 50;
//int比较小,要放进比较大的long,随便怎么样,都放的进去
l = i;
//高精度向低精度转换
byte b = 5;
int i1 = 10;
int i2 = 300;
b = (byte) i1;
//因为i1的值是在byte范围之内,所以即便进行强制转换
//最后得到的值,也是10
System.out.println(b);//10
//因为i2的值是在byte范围之外,所以就会按照byte的长度进行截取
//i2的值是300,其对应的二进制数是 100101100
//按照byte的长度8位进行截取后,其值为 00101100 即44
b =(byte) i2;
System.out.println(b);
//查看一个整数对应的二进制的方法:
System.out.println(Integer.toBinaryString(i2));
//char与short之间的转换
char c = 'A';
short s = 80;
//虽然short和char都是16位的,长度是一样的
//但是彼此之间,依然需要进行强制转换
c = (char) s;
//直接进行转换,会出现编译错误
s = c;
变量命名必须满足一系列的条件,不能随意命名
1.变量命名只能使用字母、数字、$、_
2.变量第一个字符只能使用字母、$、_
3.变量第一个字符不能使用数字
注:_ 是下划线,不是-减号或者—— 破折号
当一个变量被final修饰的时候,该变量只有一次赋值的机会;
通常final修饰的变量用来表示这是一个常量
final除了可以修饰变量,还可以修饰类,方法等
final修饰的方法表示此方法已经是“最后的、最终的”含义,亦即此方法不能被重写(可以重载多个final修饰的方法)。
此处需要注意的一点是:因为重写的前提是子类可以从父类中继承此方法,如果父类中final修饰的方法同时访问控制权限为private,将会导致子类中不能直接继承到此方法,因此,此时可以在子类中定义相同的方法名和参数,此时不再产生重写与final的矛盾,而是在子类中重新定义了新的方法。
public class B extends A {
public static void main(String[] args) {}
public void getName() {}//编译出错
private final void getName() {}//子类自己的,不出错
}
class A {
/**
* 因为private修饰,子类中不能继承到此方法,因此,子类中的getName方法是重新定义的、
* 属于子类本身的方法,编译正常
*/
private final void getName() {}
//因为 pblic修饰,子类可以继承到此方法,导致重写了父类的final方法,编译出错
public final void getName() {}
}
public void method1(final int j) {
j = 5; //这个能否执行?
}
//不可以,因为在调用方法的时候,就一定会第一次赋值了,后面不能再进行多次赋值
final修饰类即表示此类已经是“最后的、最终的”含义。因此,用final修饰的类不能被继承,即不能拥有自己的子类。如果试图对一个已经用final修饰的类进行继承,在编译期间或发生错误
其中final修饰的类:String、StringBuilder、StringBuffer、Math、UUID
、Boolean、Character、Short、Integer、Long、Float、Double、Byte、Void等
运算符用于执行程序代码运算,会针对一个及以上操作数项目来进行运算。
运算符基本分为六类:算数运算符、赋值运算符、比较/关系运算符、逻辑运算符、位运算符、三元/三目/条件运算符。
算数操作符基本的有:
i++; 先取值,再运算
++i; 先运算,再取值
-- 操作同++操作
int i = 10;
int j = 5;
int a = i+j;
int b = i - j;
int c = i*j;
int d = i /j;
/*******************************/
int i = 5;
System.out.println(i++); //输出5
System.out.println(i); //输出6
int j = 5;
System.out.println(++j); //输出6
System.out.println(j); //输出6
比较两个变量之间的关系
int a = 5;
int b = 6;
int c = 5;
System.out.println(a>b); //返回 false
System.out.println(a>=c); //返回 true
System.out.println(a==b); //返回false
System.out.println(a!=b);//返回true
//长路与 与 短路与
//长路与 无论第一个表达式的值是true或者false,第二个的值,都会被运算
int i = 2;
System.out.println( i== 1 & i++ ==2 ); //无论如何i++都会被执行,所以i的值变成了3
System.out.println(i);
//短路与 只要第一个表达式的值是false的,第二个表达式的值,就不需要进行运算了
int j = 2;
System.out.println( j== 1 && j++ ==2 ); //因为j==1返回false,所以右边的j++就没有执行了,所以j的值,还是2
System.out.println(j);
//长路或 无论第一个表达式的值是true或者false,第二个的值,都会被运算
int i = 2;
System.out.println( i== 1 | i++ ==2 ); //无论如何i++都会被执行,所以i的值变成了3
System.out.println(i);
//短路或 只要第一个表达式的值是true的,第二个表达式的值,就不需要进行运算了
int j = 2;
System.out.println( j== 2 || j++ ==2 ); //因为j==2返回true,所以右边的j++就没有执行了,所以j的值,还是2
System.out.println(j);
//取反 !
boolean b = true;
System.out.println(b); //输出true
System.out.println(!b);//输出false
//异或^
boolean a = true;
boolean b = false;
System.out.println(a^b); //不同返回真
System.out.println(a^!b); //相同返回假
int i =5;
int j = 6;
System.out.println(Integer.toBinaryString(i)); //5的二进制是101
System.out.println(Integer.toBinaryString(j)); //6的二进制是110
System.out.println(i|j); //所以 5|6 对每一位进行或运算,得到 111->7
int i =5;
int j = 6;
System.out.println(Integer.toBinaryString(i)); //5的二进制是101
System.out.println(Integer.toBinaryString(j)); //6的二进制是110
System.out.println(i&j); //所以 5&6 对每一位进行与运算,得到 100->4
int i =5;
int j = 6;
System.out.println(Integer.toBinaryString(i)); //5的二进制是 101
System.out.println(Integer.toBinaryString(j)); //6的二进制是110
System.out.println(i^j); //所以 5^6 对每一位进行或运算,得到 011->3
System.out.println(i^0);
System.out.println(i^i);
byte i =5;
System.out.println(Integer.toBinaryString(i)); //5的二进制是00000101,所以取非即为11111010,即为-6
System.out.println(~i);
/**
二进制原码:0000 0000 0000 0000 0000 0000 0000 0101
取反操作后:1111 1111 1111 1111 1111 1111 1111 1010
而在Java中,有符号整数都是用补码来表示,而补码=反码+1
1.先求反码:1000 0000 0000 0000 0000 0000 0000 0101
2.再求补码:1000 0000 0000 0000 0000 0000 0000 0110
最高位代表符号位 1 表示负数,0 表示正数 所以结果是-6
**/
byte i =6;
//6的二进制是110
System.out.println(Integer.toBinaryString(i));
//6向左移1位后,变成1100,对应的10进制是12 简单说就是 i*2^1
System.out.println(i<<1);
//6向右移1位后,变成11,对应的10进制是3 简单说就是 i/2^1
System.out.println(i>>1);
int i =-10;
//-10的二进制是11111111111111111111111111110110
//第一位是1,即符号位,代表这是一个负数
System.out.println(Integer.toBinaryString(i));
//对于正数, 带符号右移 >> 会把所有的位右移,并在最前面补0
//对于负数, 带符号右移 >> 会把所有的位右移,并在最前面补1
//-10带符号右移1位,移动后前面补齐1
//得到11111111111111111111111111111011
//因为第一位是1,所以依然是一个负数,对应的十进制是-5
int j = i>>1;
System.out.println(Integer.toBinaryString(j));
System.out.println(j);
//-10无符号向右移1位,符号位也会向右移,第一位就变成了0
//得到01111111111111111111111111111011,对应的十进制是2147483643
int k = i>>>1;
System.out.println(Integer.toBinaryString(k));
System.out.println(k);
int i = 5+5;
int i =3;
i+=2;
System.out.println(i);//5
int j=3;
j=j+2;
System.out.println(j);//5
int i = 5;
int j = 6;
int k = i < j ? 99 : 88;//5小于6为真,选第一个
System.out.println(k);//99
if(表达式1){
表达式2;
}
如果表达式1的值是true,就执行表达式2
//如果有多个表达式,必须用大括弧包括起来;如果只有一个表达式可以不用写括弧,看上去会简约一些
boolean b = false;
if(b){
System.out.println("yes1");
System.out.println("yes2");
System.out.println("yes3");
}
int i = 2;
if (i==1)
System.out.println(1);
else if (i==2)
System.out.println(2);
else if (i==3)
System.out.println(3);
else if (i==4)
System.out.println(4);
switch 语句相当于 if else的另一种表达方式
switch(表达式1){
case a: xxx; break;
case b: xxx; break;
default: xxxx
}
表达式1类型参数应该是 char, byte, short, int, Character, Byte, Short, Integer,在jdk 1.7之后,还有enum,String
//如果使用switch
int day=6
switch(day){
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期天");
break;
//都不匹配则输出这一句
default:
System.out.println("这个是什么鬼?");
}
// 方法一:
public void test4() {
flag: for (int i = 1; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (i == 2) {
break flag;
} else {
System.out.println("i=" + i + " ;j=" + j);
}
}
}
}
/**
i=1 ;j=0
i=1 ;j=1
i=1 ;j=2
i=1 ;j=3
*/
// 方法二:推荐使用
@Test
public void test5() {
boolean flag = false;
for (int i = 1; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if(i==2) {
flag = true;
}else {
System.out.println("i=" + i + " ;j=" + j);
}
}
if (flag) {
break;
}
}
}
/**
i=1 ;j=0
i=1 ;j=1
i=1 ;j=2
i=1 ;j=3
*/
//打印0到4
int i = 0;
while(i<5){
System.out.println(i);
i++;
}
//打印0到4
//与while的区别是,无论是否成立,先执行一次,再进行判断
int i = 0;
do{
System.out.println(i);
i++;
} while(i<5);
数组是一个固定长度的,包含了相同类型数据的容器
int[] a; 声明了一个数组变量。[]表示该变量是一个数组;int 表示数组里的每一个元素都是一个整数;a 是变量名
但是,仅仅是这一句声明,不会创建数组
//声明一个引用,创建一个长度是3的数组,并且使用引用a指向该数组
int[] a;
a = new int[3];
//声明的同时,指向一个数组
int[] b = new int[3];
//分配空间同时赋值
int[] c = new int[]{1, 2, 3};
int[] d = {1, 2, 3};//省略了new int[],效果一样
可以使用for、foreach;
foreach是增强for循环只能用来取值,却不能用来修改数组里的值;for可以修改数组里面的值
int values [] = new int[]{18,62,68,82,65,9};
//常规遍历
for (int i = 0; i < values.length; i++) {
int each = values[i];
System.out.println(each);
}
//增强型for循环遍历; each为临时变量,类型为数组的类型,执行过程同上面
for (int each : values) {
System.out.println(each);
}