一.java语言概述
1.JRE(运行环境)和开发环境(JDK)
运行环境包括核心API,集成API,用户界面API,发布技术,Java虚拟机(JVM)5个部分;
编译Java程序的编译器(即Javac命令)。
2.Java语言执行步骤
使用Java编译器编译Java程序时,生成的是与平台无关的字节码,这些字节码不面向任何具体的平台,只面向JVM,不同平台上的JVM都是不同的,但它们都提供了相同的接口。JVM是java程序跨平台的关键部分,只要为不同平台实现了相应的虚拟机,编译后的java字节码就可以在该平台上使用了的。
二.语法基础知识
1.一个java源文件里最多只能定义一个public类
如果Java源文件里包含public类定义,则该源文件的文件名必须与这个public类的类名相同。
HelloWorld.java
//Helloworld和A类的执行顺序以在文件中的位置运行
//此时运行则只会打印hello world
public class HelloWorld
{
//可以存在多个public的内部类
public class B{}
public class C{}
public static void main(String[] args)
{
System.out.println("Hello World!");
}
}
//这里定义public的类会引起编译报错
class A{
public static void main(String[] args){
System.out.println("printf A");
}
}
输出结果:
Hello World!
2.基本数据类型
public class IntegerValTest
{
public static void main(String[] args)
{
// 下面代码是正确的,系统会自动把56当成byte类型处理
byte a = 56;
/*
下面代码是错的,系统不会把9999999999999当成long类型处理,
所以超出int的表数范围,从而引起错误
*/
// long bigValue = 9999999999999;
// 下面代码是正确的,在巨大的整数值后使用L后缀,强制使用long类型
long bigValue2 = 9223372036854775807L;
// 以0开头的整数值是8进制的整数
int octalValue = 013;
System.out.println(octalValue);
// 以0x或0X开头的整数值是16进制的整数
int hexValue1 = 0x13;
int hexValue2 = 0XaF;
System.out.println(hexValue1);
System.out.println(hexValue2);
// 定义二个8位的二进制数
int binVal1 = 0b11010100;
byte binVal2 = 0B01101001;
// 定义一个32位的二进制数,最高位是符号位。
int binVal3 = 0B10000000000000000000000000000011;
System.out.println(binVal1); // 输出212
System.out.println(binVal2); // 输出105
System.out.println(binVal3); // 输出-2147483645
/*
定义一个8位的二进制,该数值默认占32位,因此它是一个正数。
只是强制类型转换成byte时产生了溢出,最终导致binVal4变成了-23
*/
byte binVal4 = (byte)0b11101001;
/*
定义一个32位的二进制数,最高位是1。
但由于数值后添加了L后缀,因此该整数的实际占64位,第32位的1不是符号位。
因此binVal5的值等于2的31次方 + 2 + 1
*/
long binVal5 = 0B10000000000000000000000000000011L;
System.out.println(binVal4); // 输出-23
System.out.println(binVal5); // 输出2147483651
}
}
3.数值中使用下划线分隔,Java7中引入的一个新功能:
程序员可以在数值中使用下划线,不管是整型数值,还是浮点数值,都可以自由地使用下划线。
public class UnderscoreTest
{
public static void main(String[] args)
{
// 定义一个32位的二进制数,最高位是符号位。
int binVal = 0B1000_0000_0000_0000_0000_0000_0000_0011;
double pi = 3.14_15_92_65_36;
System.out.println(binVal);
System.out.println(pi);
double height = 8_8_4_8.23;
System.out.println(height);
}
}
4.自动类型装换
AutoConversion.java
public class AutoConversion
{
public static void main(String[] args)
{
int a = 6;
// int可以自动转换为float类型
float f = a;
// 下面将输出6.0
System.out.println(f);
// 定义一个byte类型的整数变量
byte b = 9;
// 下面代码将出错,byte型不能自动类型转换为char型
// char c = b;
// 下面是byte型变量可以自动类型转换为double型
double d = b;
// 下面将输出9.0
System.out.println(d);
}
}
public class PrimitiveAndString
{
public static void main(String[] args)
{
// 下面代码是错的,因为5是一个整数,不能直接赋给一个字符串
// String str1 = 5;
// 一个基本类型值和字符串进行连接运算时,基本类型值自动转换为字符串
String str2 = 3.5f + "";
// 下面输出3.5
System.out.println(str2);
// 下面语句输出7Hello!
System.out.println(3 + 4 + "Hello!");
// 下面语句输出Hello!34,因为Hello! + 3会把3当成字符串处理,
// 而后再把4当成字符串处理
System.out.println("Hello!" + 3 + 4);
}
}
5.Java7增强后的Switch分支语句
switch语句后面的控制表达式的数据类型只能是byte,short,char,int四种整数类型,枚举类型和java.lang.String类型,不能是boolean类型。
public class StringSwitchTest
{
public static void main(String[] args)
{
// 声明变量season
String season = "夏天";
// 执行swicth分支语句
switch (season)
{
case "春天":
System.out.println("春暖花开.");
break;
case "夏天":
System.out.println("夏日炎炎.");
break;
case "秋天":
System.out.println("秋高气爽.");
break;
case "冬天":
System.out.println("冬雪皑皑.");
break;
default:
System.out.println("季节输入错误");
}
}
}
6.break和continue的使用
java中的标签只有放在循环语句之前才有作用。break outer语句将会导致结束outer标签指定的循环。
BreakTest.java
public class BreakTest
{
public static void main(String[] args)
{
//1. 外层循环,outer作为标识符
outer:
for (int i = 0 ; i < 5 ; i++ )
{
// 2. 内层循环
//如果把这个标签放在break语句所在的循环之前定义,也就失去了标签的意义,
//因为break默认就是结束其所在的循环。
// outer:
for (int j = 0; j < 3 ; j++ )
{
System.out.println("i的值为:" + i + " j的值为:" + j);
if (j == 1)
{
// 跳出outer标签所标识的循环。
break outer;
}
}
}
//跳出循环后会执行到这条语句
System.out.println("excute!");
}
}
结果:
1.外层循环:
i的值为:0 j的值为:0
i的值为:0 j的值为:1
2.内层循环:
i的值为:0 j的值为:0
i的值为:0 j的值为:1
i的值为:1 j的值为:0
i的值为:1 j的值为:1
i的值为:2 j的值为:0
i的值为:2 j的值为:1
i的值为:3 j的值为:0
i的值为:3 j的值为:1
i的值为:4 j的值为:0
i的值为:4 j的值为:1
excute!
所以通常紧跟break之后的标签,必须在break所在循环的外层循环之前定义才有意义。
continue用于直接跳过标签所标识循环的当次循环的剩余语句,重新开始下一次循环.
ContinueTest.java
public class ContinueTest
{
public static void main(String[] args)
{
// 外层循环
outer:
for (int i = 0 ; i < 5 ; i++ )
{
// 内层循环
for (int j = 0; j < 3 ; j++ )
{
System.out.println("i的值为:" + i + " j的值为:" + j);
if (j == 1)
{
// 忽略outer标签所指定的循环中本次循环所剩下语句。
continue outer;
}
}
}
//执行不到这里来的
System.out.println("excutes");
}
}
结果:
i的值为:0 j的值为:0
i的值为:0 j的值为:1
i的值为:1 j的值为:0
i的值为:1 j的值为:1
i的值为:2 j的值为:0
i的值为:2 j的值为:1
i的值为:3 j的值为:0
i的值为:3 j的值为:1
i的值为:4 j的值为:0
i的值为:4 j的值为:1
excutes
7.定义初始化数组
数组的初始化有如下两种方式:
静态初始化:初始化时由程序员显式指定每个数组元素的初始值,由系统决定数组长度。
动态初始化:初始化时程序员只指定数组长度,由系统为数组元素分配初始值。
public class ArrayTest
{
public static void main(String[] args)
{
// 定义一个int数组类型的变量,变量名为intArr.
int[] intArr;
// 使用静态初始化,初始化数组时只指定数组元素的初始值,不指定数组长度。
intArr = new int[]{5, 6, 8 , 20};
// 定义一个Object数组类型的变量,变量名为objArr.
Object[] objArr ;
// 使用静态初始化,初始化数组时数组元素的类型是
// 定义数组时所指定的数组元素类型的子类
objArr = new String[]{"Java" , "李刚"};
Object[] objArr2 ;
// 使用静态初始化
objArr2 = new Object[] {"Java" , "李刚"};
// 数组的定义和初始化同时完成,使用简化的静态初始化写法
int[] a = {5, 6 , 7, 9};
//数组的定义和初始化同时完成,使用动态初始化语法
int[] prices = new int[5];
// 数组的定义和初始化同时完成,初始化数组时元素的类型是定义数组时元素类型的子类
Object[] books = new String[4];
// 输出objArr数组的第二个元素,将输出字符串"李刚"
System.out.println(objArr[1]);
// 为objArr2的第一个数组元素赋值
objArr2[0] = "Spring";
// 访问数组元素指定的索引等于数组长度,所以下面代码将在运行时出现异常
// System.out.println(objArr2[2]);
// 使用循环输出prices数组的每个数组元素的值
for (int i = 0; i < prices.length ; i ++ )
{
System.out.println(prices[i]);
}
// 对动态初始化后的数组元素进行赋值
books[0] = "疯狂Java讲义";
books[1] = "轻量级Java EE企业应用实战";
// 使用循环输出books数组的每个数组元素的值
for (int i = 0 ; i < books.length ; i++ )
{
System.out.println(books[i]);
}
}
}
注意:不要同时使用静态初始化和动态初始化,也就是说,不要在进行数组初始化时,既指定数组的长度,也为每个数组元素分配初始值。
如:
int[] prices = new int[5] {1,2,3,4,5};//error
8.foreach循环
使用foreach循环迭代数组元素时,并不能改变数组元素的值,因此不要对foreach的循环变量进行赋值。
public class ForEachTest
{
public static void main(String[] args)
{
String[] books = {"轻量级Java EE企业应用实战" ,
"疯狂Java讲义",
"疯狂Android讲义"};
// 使用foreach循环来遍历数组元素,
// 其中book将会自动迭代每个数组元素
for (String book : books)
{
System.out.println(book);
}
}
}
结果:
轻量级Java EE企业应用实战
疯狂Java讲义
疯狂Android讲义
9.Java8增加的工具类:Arrays
java里面提供的Arrays类里包含的一些static修饰的方法可以直接操作数组(static修饰的方法可以直接通过类名调用)
ArraysTest.java
import java.util.Arrays;
public class ArraysTest
{
public static void main(String[] args)
{
// 定义一个a数组
int[] a = new int[]{3, 4 , 5, 6};
// 定义一个a2数组
int[] a2 = new int[]{3, 4 , 5, 6};
// a数组和a2数组的长度相等,每个元素依次相等,将输出true
System.out.println("a数组和a2数组是否相等:"
+ Arrays.equals(a , a2));
// 通过复制a数组,生成一个新的b数组
int[] b = Arrays.copyOf(a, 6);
System.out.println("a数组和b数组是否相等:"
+ Arrays.equals(a , b));
// 输出b数组的元素,将输出[3, 4, 5, 6, 0, 0]
System.out.println("b数组的元素为:"
+ Arrays.toString(b));
// 将b数组的第3个元素(包括)到第5个元素(不包括)赋为1
Arrays.fill(b , 2, 4 , 1);
// 输出b数组的元素,将输出[3, 4, 1, 1, 0, 0]
System.out.println("b数组的元素为:"
+ Arrays.toString(b));
// 对b数组进行排序
Arrays.sort(b);
// 输出b数组的元素,将输出[0, 0, 1, 1, 3, 4]
System.out.println("b数组的元素为:"
+ Arrays.toString(b));
}
}
10.垃圾回收机制
1> Java程序的内存分配和回收都是由JRE在后台自动进行的。JRE会负责回收那些不再使用的内存,这种机制被称为垃圾回收。
2> 通常JRE会提供一个后台线程来进行检测和控制,一般都是在CPU空闲或内存不足时自动进行垃圾回收;
3> 垃圾回收是一种动态存储管理技术,它自动释放不再被程序引用的对象,按照特定的垃圾回收算法来实现内存资源的自动回收功能。
4> 虽然程序员可以通过调用Runtime对象的gc()或System.gc()等方法来建议系统进行垃圾回收,但这种调用仅仅是建议,依然不能精确控制垃圾回收机制的执行。