01. class VarDemo
02. {
03. public static void main(String[] args){
04. long l = 123456789123;
05. System.out.println(l);
06. }
07. }
错误原因:由于整数默认类型是int类型,如果数值超过了int类型的范围,那么就会报如上错误。即使
是赋值给long类型的变量,但是由于后面的常量已经超过了int类型的范围,同样会报错。
解决方法:在数值后面加上一个”L”,就可以让编译器知道后面的常量是long类型。
01. class VarDemo
02. {
03. public static void main(String[] args){
04. float f = 2.3;
05. System.out.println(f);
06. }
07. }
错误原因:由于小数默认是double(8byte)类型,赋值给float(4byte)类型的变量,当然可能会损
失精度,必然通不过编译器的审核。
解决方法:在数值后面加上一个“f”,让编译器知道后面的常量是float类型的
类型转换
1.自动类型转换(隐式类型转换)
定义:自动类型转换就是不需要我们手动对类型来进行强制转换。
int类型的变量占4个字节,当byte类型的变量与其相加的时候,首先会将byte类型的变量自动转化为4个字节的int类型,然后再进行加法操作。
2.强制类型转换(显式类型转换)
定义:强制类型转换需要把类型进行手动转换,否则无法正常使用
01. class VarDemo
02. {
03. public static void main(String[] args){
04. byte b = 3;
05. b = b + 200;
06. System.out.println(b);
07. }
08. }
错误原因:当byte类型的变量提升为int类型与int类型的常量200相加后,结果依然是int类型,再赋值给byte类型,当然会出现损失精度的错误。
解决方法:进行强制类型转换,也就是将占4个字节的int类型值,再强硬存储到占1个字节的byte变量中
01. class VarDemo
02. {
03. public static void main(String[] args){
04. byte b = 3;
05. b = (byte)(b + 200);
06. System.out.println(b);
07. }
08. }
说明:结果为-53的原因是,200+3结果是203,换算成占1个字节空间的二进制也就是11001011。
由于首位为1,所以是负数,除符号位外,其余部分取反加1,得1,0110101,即-53。
1、只有数值类型才能进行加法操作,非数值类型不行。
2、char类型数据也可以和int类型相加,但是首先char类型数据会被自动提升为int类型。
01. class VarDemo
02. {
03. public static void main(String[] args){
04. System.out.println('a'+1);
05. System.out.println('你'+1);
06. }
07. }
说明:字符类型数据之所以能够自动提升为int类型是因为字符类型数据在计算机中也是用0、1表示的,int类型数据在计算机中也用0、1表示,所以char类型数据当然可以转换为int类型数据。但是,字符类型数据在计算机中使用0、1表示是按照何种顺序组合排列的则需要依据某个码表而定。Java中的内置码表是Unicode,既包含中文,也包含英文,通过强转也可以把数字强转成字符。
01. class VarDemo
02. {
03. public static void main(String[] args){
04. System.out.println((char)('a'+1));
05. }
06. }
表达式的数据类型自动提升:
所有的byte型、short型和char的值将被提升到int型。
如果一个操作数是long型,计算结果就是long型;
如果一个操作数是float型,计算结果就是float型;
如果一个操作数是double型,计算结果就是double型。
01. classVarDemo
02. {
03. publicstaticvoidmain(String[]args){
04. byteb=3+7;
05. byteb1=3;
06. byteb2=7;
07. b=b1+b2;
08.
09. System.out.println(b)
10. }
11. }
错误原因:涉及到编译器编译程序时候的细节,之所以byteb=3+7;,没有报错,是因为3和7都是常量,编译器知道结果是10,并且在byte范围之内,因此就自动进行了强转,所以不会报错。而b=b1+b2;中b1和b2都是变量,编译器编译程序是一行一行编译的,它根本不知道b1和b2到底是多少,两个byte类型的数据相加时,首先都会被提升为int类型,他们的和也是int类型,其值可能会超过byte的范围,因此就会报错。
01. class VarDemo
02. {
03. public static void main(String[] args){
04. int x;
05. int x1 = Integer.MAX_VALUE;
06. int x2 = 2;
07. x = x1 + x2;
09. System.out.println(x);
10. }
11. }
说明:原因是因为int类型的两个变量相加,最后还是int类型,虽然结果溢出但是不会报错,只是结果是负数
负数对正数取模结果为负数。
正数对负数取模结果为正数。
比较s+=4;和s=s+4;的不同
01. class OperatorDemo
02. {
03. public static void main(String[] args){
04. short s = 3;
05. s += 4;
06. System.out.println("s = " + s);
07. }
08. }
说明:在执行s+=4;语句时,编译器在编译的时候,默认进行了强制类型转换,也就是将int类型的数据转换成short类型的数据。
01. class OperatorDemo
02. {
03. public static void main(String[] args){
04. short s = 3;
05. s = s + 4;
06. System.out.println("s = " + s);
07. }
08. }
说明:在执行s=s+4;语句时,编译器在编译的时候,默认并没有强制类型转换。所以,s是short类型,4是int类型,s会自动提升为int类型,相加的和也是int类型,赋值给short类型的变量肯定会损失精度。这时候就需要进行强制类型转换:s=(short)(s+4);。
运算符
比较运算符的结果都是boolean型,也就是要么是true,要么是false。
"&"符号运算规律:
运算的两边只要有一个是false,结果肯定是false。
只有两边都为true,结果才是true。
"|"符号的运算特点:
true|true=true;
true|false=true;
false|true=true;
false|false=false;
"^"符号的运算特点:
true^true=false;
true^false=true;
false^true=true;
false^false=false;
&&:和&运算的结果是一样的,但是运算过程有点小区别。
&:无论左边的运算结果是什么,右边都参与运算。
&&:当左边为false时,右边不参加运算,这样可以提升效率。
||:和|运算的结果是一样的,但是运算过程有点小区别。
|:无论左边的运算结果是什么,右边都参与运算。
||:当左边为true时,右边不参加运算,这样可以提升效率。
1.6.5 三元运算符
格式:
(条件表达式)?表达式1:表达式2;
如果条件为true,运算后的结果是表达式1;
如果条件为false,运算后的结果是表达式2。
if语句
格式一:
if(条件表达式)
{
执行语句;
}
格式二:
if(条件表达式)
{
执行语句;
}
else
{
执行语句;
}
if(表达式)后面切忌加上分号,否则表示无论表达式为true或者false,都不执行任何语句.
01. class IfDemo{
03. public static void main(String[] args){
04. if( false );{
06. System.out.println("Hello World!");
07. }
08. }
09. }
说明:由于if(false);语句后面加了分号,因此不执行任何操作。{System.out.println("HelloWorld");}为局部代码块。
switch语句特点:
1、switch语句选择的类型只有四种:byte,short,int,char,包括字符串。
2、case与default没有顺序。先执行第一个case,没有匹配的case执行default。
3、结束switch语句的两种情况:①遇到break,②执行到switch语句结束。
4、如果匹配的case或者default没有对应的break,那么程序会继续向下执行,运行可以执行的语句,直到遇到break或者switch结尾结束。
5、进入switch语句后,执行顺序是先执行case,然后从上到下,最后再执行default。即使default放在case上面,执行顺序也不变。
while和dowhile的区别:
dowhile语句的特点:无论条件是否满足,循环体至少执行一次。
while如果条件不满足,循环体一次都不会执行。
2、最简单无限循环格式:while(true),for(;;),无限循环存在的原因是并不知道循环多少次,而是根据某些条件,来控制循环。
1、 在使用循环时候,一定要明确哪些语句需要参与循环,哪些不需要。循环通常情况下,需要定义条件,需要控制次数。
1、代码中的"\t"是一个转义字符,也就是制表符。还有其他的一些转义字符:\n:回车,\b:退格,\r:回车符。
2、windows系统中回车符其实是由两个转义字符组成的:\r\n,linux中回车符是\n。
例子:
打印"helloworld":
System.out.println("\"helloword\"");
打印\helloworld\:
System.out.println("\\helloword\\");
1.7.4 其他流程控制语句
break(跳出),continue(继续)。
break语句:
应用范围:选择结构和循环结构。
continue语句:
应用范围:循环结构。
continue语句是结束本次循环继续下次循环。
P.S.
1、这两个语句离开应用范围,存在是没有意义的。
2、这个两个语句单独存在,下面都不可以有语句,因为执行不到。
1.8.1 函数的定义
函数就是定义在类中的具有特定功能的一段独立小程序,函数也称为方法。
函数的格式:
修饰符返回值类型函数名(参数类型形式参数1,参数类型形式参数2,...)
{
执行语句;
return返回值;
}
返回值类型:函数运行后的结果的数据类型。
参数类型:是形式参数的数据类型。
形式参数:是一个变量,用于存储调用函数时传递给函数的实际参数。
实际参数:传递给形式参数的具体数值。
return:用于结束函数。
返回值:该函数运算后的结果,该结果会返回给调用者。
1、对于函数没有具体返回值的情况,返回值类型用关键字void表示,那么该函数中的return语句如果在最后
1.8.4 函数的重载
重载的概念:
在同一个类中,允许存在一个以上的同名函数,只要它们的参数个数或者参数类型不同即可。一行可以省略不写,或者写上return;
2、函数中只能调用函数,不可以在函数内部定义函数。否则,编译时期就会报错。
总结:
函数的功能一样,仅仅是参与运算的未知内容不同时,可以定义多函数,却使用统一函数名称,这样方便阅读。在调用时,虚拟机通过参数列表的不同来区分同名函数。
P.S.
1、重载与返回值类型无关,只看参数列表。
2、java是严谨性语言,如果函数调用出现不确定性,会编译失败。
栈内存:
用于存储局部变量,当变量所属的作用域一旦结束,所占空间会自动释放。
堆内存:
数组和对象,通过new建立的实例都存放在堆内存中。
每一个实体都有内存地址值。即便数组名不同,但是如果指向同一个地址,那么改变数组项后,两个数组的对应元素都改变.
实体中的变量都有默认初始化值,根据类型的不同而不同。整数类型是0,小数类型是0.0或0.0f,boolean类型是false,char类型是'\u0000',字符串类型为null。
如果将数组的引用实体(数组名,也就是说只想该数组地址的数组名)设置为null,也就是实体不再被使用,那么会在不确定的时间内被垃圾回收器回收。这种情况下如果你还去访问数组的数组项,就会导致空指针问题.
01. class ArrayDemo{
02. public static void main(String[] args){
03. int[] arr = null;
04. System. out.println(arr[0]);
05. }
06. }
空指针异常(NullPointerException):当引用型变量没有指向任何实体时,用其操作实体,就会发生该异常。
数组
二维数组[][]
格式1:
int[][]arr=newint[3][2];
格式2:
int[][]arr=newint[3][];
二维数组中有3个一维数组,每个一维数组都是默认初始化值null,可以对这个三个一维数组分别进行初始化。
01. class Array2Demo
02. {
03. public static void main(String[] args){
04. int[][] arr = new int[3][];
05. System.out.println(arr);
06. System.out.println(arr[0]);
07. System.out.println(arr[0][0]); //报错
08. }
09. }
示例中arr[0]为null的原因是没有为它初始化一位数组。
由于arr[0]为null,通过它获取一维数组角标为0的元素肯定会报空指针异常错误!
格式3:
int[][]arr={{3,8,2},{2,7},{9,0,1,6}};
选择排序:
11. public static void selectSort(int[] arr){
12. for(int x = 0; x < arr.length - 1; x++){
13. for(int y = x + 1; y < arr.length; y++){
14. if(arr[x] > arr[y]){
15. int temp = arr[x];
16. arr[x] = arr[y];
17. arr[y] = temp;
18. }
19. }
20. }
21. }
方法二:
那么更高效率的方式则是只需要通过两个变量,一个记录最小值,一个记录最小值所在
的角标即可。等当前元素与余下的所有元素比较完,直接互换,这样只需互换一次就能达到目标,效率自然就会提高。
11. public static void selectSort(int[] arr){
12. for(int x = 0; x < arr.length - 1; x++){
13. int num = arr[x];
14. int index = x;
15. for(int y = x + 1; y < arr.length; y++){
16. if(num > arr[y]){
17. num = arr[y];
18. index = y;
19. }
20. }
21. //如果最小的就是自己,就没有必要执行swap操作
22. if(index != x)
23. swap(arr,x,index);
24. }
25. }
26.//交换地址
27. public static void swap(int[] arr, int a,int b){
28. int temp = arr[a];
29. arr[a] = arr[b];
30. arr[b] = temp;
31. }
冒泡排序:
11. public static void bubbleSort(int[] arr){
12. for(int x = 0; x < arr.length - 1; x++){
13. for(int y = 0; y < arr.length - 1 -x; y++){
14. if(arr[y] > arr[y+1]){
15. int temp = arr[y];
16. arr[y] = arr[y+1];
17. arr[y+1] = temp;
18. }
19. }
20. }
21. }
二分法查找:
思路:
1、设置三个变量记录角标:min、max、mid。min初始值为0,max为数组最大角标,mid为
(max+min)/2。
2、查看mid角标的元素是否与待查找的值相等,如果相等,则直接返回角标值,程序终止执行。
3、如果待查找的值小于角标为mid的元素值,那么说明待查找的元素的位置可能在min与mid角标之间。设
置max=mid-1,mid=(max+min)/2,重复第1、2步的操作。
4、如果待查找的值大于角标为mid的元素值,那么说明待查找的元素的位置可能在mid与max角标之间。设
置min=mid+1,mid=(max+min)/2,重复第1、2步的操作。
5、如果数组中不存在待查找的元素,那么按照如上流程,最终min角标值会大于max角标值,此时返回-1。
08. public static int binarySearch(int[] arr, int key){
09. int max,min,mid;
10. min = 0;
11. max =arr. length - 1;
12. mid = (max + min)/2;
14. while(arr[mid] !=key){
15. if(key > arr[mid])
16. min = mid + 1;
17. else if (key < arr[mid])
18. max = mid - 1;
19. if(max < min)
20. return -1;
21. mid = (max + min)/2;
22. }
23. return mid;
24. }
25. }
08. public static int binarySearch(int[] arr, int key){
09. int max,min,mid;
10. min = 0;
11. max = arr. length - 1;
12.
13. while(min <= max){ //因为有min<=max,所以while循环必进.
14. mid = (max + min) >> 1;
15.
16. if(key > arr[mid])
17. min = mid + 1;
18. else if (key < arr[mid])
19. max = mid - 1;
20. else
21. return mid;
22. }
23. return -1; //只是作为占位使用,避免报错
24. }
25. }
面对对象
3.2.2 类的定义
类可以看作一个数据类型,里面每一个元素就是类对像的数组.
同时还可以返回整个对象.
示例:
package classlearn;
public class User {
String username;
String password;
double balance;
}
User [] users = new User[3];创建一个有三个对象的对象数组.
生活中描述事物无非就是描述事物的属性和行为.
Java中用类class来描述事物也是如此。
属性:对应类中的成员变量。
行为:对应类中的成员函数。
定义类其实在定义类中的成员(成员变量和成员函数)。
3.2.3 成员变量和局部变量的区别?
成员变量:
1.成员变量定义在类中,在整个类中都可以被访问。
2.成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。
3.成员变量有默认初始化值。
局部变量:
1.局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效。
2.局部变量存在于栈内存中,作用的范围结束,变量空间会自动释放。
3.局部变量没有默认初始化值。
3.2.5 对象内存结构
Carc1=newCar();
c1.color="blue";
Carc2=newCar();
内存结构示意图:
只要是用new操作符定义的实体就会在堆内存中开辟一个新的空间,并且每一个对象中都有一份属于自己的属性。
通过对象.对象成员的方式操作对象中的成员,对其中一个对象的成员进行了修改,和另一个对象没有任何关系。
需要提到的是c1、c2都是对实体的引用变量,如果执行c2=c1,那么c2也就指向了c1引用的实体。c2原来引用的实体因为没有被引用变量引用,就会被垃圾回收器回收。但是此时如果设定c1 = null;只是释放了c1中的地址,而c2中依然存着实例的地址.c2实例的各种属性还是能够被调用.
3.2.6 匿名对象
匿名对象是对象的简化形式。
匿名对象两种使用情况:
1.当对对象方法仅进行一次调用时;
2.匿名对象可以作为实际参数进行传递。