JavaSE基础知识总结

1.变量和数据类型与运算符

Java是一种强类型的语言。这就意味着必须为每一个变量声明一种类型。在Java中,一共有8中基本类型(primitive type),其中有4种整型、2种浮点类型、1种用于表示Unicode编码的字符单元的字符类型char和1种用于表示真值的boolean类型。

1.1什么是变量:

这里讨论的变量主要是和内存密切相关的,变量由于要用来保存数据,所以需要一块空间,这块空间就在“内存上”。

1.2变量的定义与使用:
        int a;  //定义一个变量
        int b=7; //定义一个变量并且赋值为7
        a=3; //将变量a赋值为3
        System.out.println(b); //打印出变量b里面保存的数据

总结:

  1. 变量必须先定义,才能被使用。

  2. 变量如果先被赋值或者初始化,才能被使用

1.3数据类型:

在这里插入图片描述

1.3.1整型:

整型用于表示没有小数部分的数值,它允许是负数。Java提供了4种整型,具体如下:

整数			占用字节数
byte		   	 1
short			 2
int			     4
long			 8

什么是字节:

字节是计算机中表示空间大小的基本单位.

计算机使用二进制表示数据. 我们认为 8 个二进制位(bit) 为一个字节(Byte).

我们平时的计算机为 8GB 内存, 意思是 8G 个字节.

其中 1KB = 1024 Byte, 1MB = 1024 KB, 1GB = 1024 MB.

所以 8GB 相当于 80 多亿个字节.

一般情况下,整数默认是int类型;byte和short类型一般用于一些特定的场景,比如说一些底层的文件操作;long类型一般不会怎么使用,但是一般用来处理一些特别大的数据;要注意的是定义long类型要用后缀用L或者l标记。

1.3.2浮点型:

浮点类型用于表示有小数部分的数值。在Java中有两种浮点类型,如下:

浮点数			占用字节数
float 			  4
double 			  8

double表示这种类型的数值精度是float类型的两倍(又称双精度数值)。绝大数的应用程序都采用double类型。在很多情况下,float类型的精度很难满足需求。比如:需要快速地处理单精度数据,或者需要存储大量数据。
float类型的数值有一个后缀F(例如:3.14F)。没有后缀F的浮点数组默认为double类型。当然,也可以在浮点数值后面添加后缀D(例如:3.14D)。
要注意的是:单精度浮点数用F或者f标记。

1.3.3char类型:

基本格式:

char 变量名=初始值;

代码示例:

char ch='a';

注意事项:

  1. Java 中使用 单引号 + 单个字母 的形式表示字符字面值.

  2. 计算机中的字符本质上是一个整数. 在 C 语言中使用 ASCII 表示字符, 而 Java 中使用 Unicode 表示字符. 因此一个字符占用两个字节, 表示的字符种类更多, 包括中文.

1.3.4boolean类型:

基本格式:

boolean 变量名=初始值;

代码示例:

 boolean h=true;
 System.out.println(h);

注意事项:

  1. boolean 类型的变量只有两种取值, true 表示真, false 表示假.
  2. Java 的 boolean 类型和 int 不能相互转换, 不存在 1 表示 true, 0 表示 false 这样的用法.
  3. boolean 类型有些 JVM 的实现是占 1 个字节, 有些是占 1 个比特位, 这个没有明确规定.
1.3.5数据类型转换:

1.int long/double 相互赋值:

int a = 10;
long b = 20;
a = b;  // 编译出错, 提示可能会损失精度. 
b = a; // 编译通过. 
int a = 10;
double b = 1.0; 
a = b;  // 编译出错, 提示可能会损失精度.
 b = a;// 编译通过.

long 表示的范围更大, 可以将 int 赋值给 long, 但是不能将 long 赋值给 int.

double 表示的范围更大, 可以将 int 赋值给 double, 但是不能将 double 赋值给 int.

结论: 不同数字类型的变量之间赋值, 表示范围更小的类型能隐式转换成范围较大的类型, 反之则不行.

2.int 和 boolean 相互赋值:

int a = 10;
boolean b = true;
b = a; // 编译出错, 提示不兼容的类型
a=b;// 编译出错, 提示不兼容的类型

结论: int与boolean是毫不相关的类型,不能相互赋值。

3.int字面值常量给byte赋值:

byte a = 100;// 编译通过
byte b = 256; // 编译报错, 提示 从int转换到byte可能会有损失

注意: byte 表示的数据范围是 -128 -> +127, 256 已经超过范围, 而 100 还在范围之内.

结论: 使用字面值常量赋值的时候, Java 会自动进行一些检查校验, 判定赋值是否合理.

4. int 和 String 之间的相互转换:
1.int 转成 String:

int num = 10;
// 方法1
String str1 = num + "";  
// 方法2
String str2 = String.valueOf(num);

2.String 转成 int:

String str = "100";
int num = Integer.paserInt(str);

5.使用强制类型转换:

int a = 0;
double b = 10.5; a = (int)b;
int a = 10;
boolean b = false; b = (boolean)a; // 编译出错, 提示不兼容的类型

结论: 使用 (类型) 的方式可以将 double 类型强制转成 int. 但是

  1. 强制类型转换可能会导致精度丢失. 如刚才的例子中, 赋值之后, 10.5 就变成 10 了, 小数点后面的部分被忽略.

  2. 强制类型转换不是一定能成功, 互不相干的类型之间无法强转!

6.自动装箱与自动拆箱:

其实每种内置类型的数据都对应了一个包装类,其中以int类型为例,来介绍一下,自动装箱与自动拆箱的机制:

     //自动装箱
        Integer a=12;  //实际会隐式调用 Integer.valueOf()方法
        System.out.println(a);
        Integer b=new Integer(30);
        //自动拆箱
        int num=b;   //实际会隐式调用b.intvalueOf()方法
        System.out.println(b);
1.3.6数值提升:

**1.**int 和 long 混合运算:

int a = 10;
long b = 20;
int c = a + b; // 编译出错, 提示将 long 转成 int 会丢失精度
long d = a + b; //编译通过

结论: 当 int 和 long 混合运算的时候, int 会提升成 long, 得到的结果仍然是 long 类型, 需要使用 long 类型的变量来接收结果. 如果非要用 int 来接收结果, 就需要使用强制类型转换.
**2.**byte 和 byte 的运算:

byte a = 10;
byte b = 20;
byte c = a + b;
System.out.println(c);
// 编译报错
Test.java:5: 错误: 不兼容的类型:int转换到byte可能会有损失

结论: byte 和 byte 都是相同类型, 但是出现编译报错. 原因是, 虽然 a 和 b 都是 byte, 但是计算 a + b 会 先将 a 和 b 都提升成 int, 再进行计算, 得到的结果也是 int, 这是赋给 c, 就会出现上述错误. 由于计算机的 CPU通常是按照 4 个字节为单位从内存中读写数据. 为了硬件上实现方便, 诸如 byte 和 short 这种低于 4 个字节的类型, 会先提升成 int, 再参与计算.

正确的写法:

byte a = 10;
byte b = 20;
byte c = (byte)(a + b);
System.out.println(c);

类型提升小结:
1. 不同类型的数据混合运算, 范围小的会提升成范围大的.
2. 对于 short, byte 这种比 4 个字节小的类型, 会先提升成 4 个字节的 int , 再运算。

1.4运算符

1.赋值运算符:
这个运算符在数学中叫做“等于”,下面来看一下代码:

int a=12;
a=10;//这里的等号就是赋值运算符

2.算术运算符:
a) int / int 结果还是 int, 需要使用 double 来计算:

int a = 1;
int b = 2;
System.out.println(a / b);
// 结果为 0

b) 0 不能作为除数:

int a = 1;
int b = 0;
System.out.println(a / b)
    
// 运行时异常
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Test.main(Test.java:5)

c) % 表示取余, 不仅仅可以对 int 求模, 也能对 double 来求模:

System.out.println(11.5 % 2.0);
// 输出结果
1.5

d)增量赋值运算符:

int a = 10;
a += 1; // 等价于 a = a + 1
System.out.println(a);

e)自增/自减运算

int a=10;
int b=++a;
int c=a--;
System.out.println(a);
System.out.println(b);

结论:
1. 如果不取自增运算的表达式的返回值, 则前置自增和后置自增没有区别.
2. 如果取表达式的返回值, 则前置自增的返回值是自增之后的值, 后置自增的返回值是自增之前的值

3.关系运算符:
关系运算符主要有六个:
== != < > <= >=

int a = 10;
int b = 20;
System.out.println(a == b);
System.out.println(a != b);
System.out.println(a < b);
System.out.println(a > b);
System.out.println(a <= b);
System.out.println(a >= b);

4.逻辑运算符:
逻辑运算符主要有三个:
&& || !
注意: 逻辑运算符的操作数(操作数往往是关系运算符的结果)和返回值都是 boolean.

逻辑与 &&
规则: 两个操作数都为 true, 结果为 true, 否则结果为 false.

int a = 10;
int b = 20;
int c = 30;
System.out.println(a>b && a<b);

逻辑或 ||
规则: 两个操作数都为 false, 结果为 false, 否则结果为 true.

int a = 10;
int b = 20;
int c = 30;
System.out.println(a < b || b < c);

逻辑非 !
规则: 操作数为 true, 结果为 false; 操作数为 false, 结果为 true(这是个单目运算符, 只有一个操作数).

int a = 10;
int b = 20;
System.out.println(!a<b);

路求值
&& 和 || 遵守短路求值的规则.

System.out.println(10 > 20 && 10 / 0 == 0);   // 打印 false
System.out.println(10 < 20 || 10 / 0 == 0);    // 打印 true

我们都知道, 计算 10 / 0 会导致程序抛出异常. 但是上面的代码却能正常运行, 说明 10 / 0 并没有真
正被求值.

结论:
1. 对于 && , 如果左侧表达式值为 false, 则表达式的整体的值一定是 false, 无需计算右侧表达式.
2. 对于 ||, 如果左侧表达式值为 true, 则表达式的整体的一定式true,无需计算右侧的值!

& 和 |
& 和 | 如果操作数为 boolean 的时候, 也表示逻辑运算. 但是和 && 以及 || 相比, 它们不支持短路求值。

System.out.println(10 > 20 && 10 / 0 == 0);   // 抛异常
System.out.println(10 < 20 || 10 / 0 == 0);    // 抛异常

5. 位运算符:
Java 中对数据的操作的最小单位不是字节, 而是二进制位.
位运算符主要有四个:
& | ~ ^
位操作表示 按二进制位运算. 计算机中都是使用二进制来表示数据的(01构成的序列), 按位运算就是在按照二进制位的每一位依次进行计算.

按位与 &: 如果两个二进制位都是 1, 则结果为 1, 否则结果为 0:

int a=10;
int b=20;
System.out.println(a&b);

进行按位运算, 需要先把 10 和 20 转成二进制, 分别为 1010 和 10100

按位或 |: 如果两个二进制位都是 0, 则结果为 0, 否则结果为 1.

int a=10;
int b=20;
System.out.println(a|b);

按位取反 ~: 如果该位为 0 则转为 1, 如果该位为 1 则转为 0

int a = 0xf;
System.out.printf("%x\n", ~a)
====================================
         int a=10;
        double s=(int)2; //相当于与没写,这个相当于精度提升,但是不能向下转
        //计算机存储的是补码 正数的原码反码补码相同
        //  10==> 01010  =>按位取反  10101==>得到后要转成补码,先取反码 ==>11010 再加一变成补码
        // ==> 11011 ==>第一位为符号位所以是 -11
        System.out.println(~a);
        System.out.println(s);

注意:

  1. 0x 前缀的数字为 十六进制 数字. 十六进制可以看成是二进制的简化表示方式. 一个十六进制数字对
    应 4 个二进制位.
  2. 0xf 表示 10 进制的 15, 也就是二进制的 1111
  3. printf 能够格式化输出内容, %x 表示按照十六进制输出.
  4. \n 表示换行符

按位异或 ^: 如果两个数字的二进制位相同, 则结果为 0, 相异则结果为1

int a = 0x1;
int b = 0x2;
System.out.printf("%x\n", a ^ b);

6.移位运算
移位运算符有三个:
<< >> >>>
都是按照二进制位来运算。
左移 <<: 最左侧位不要了, 最右侧补 0。

int a = 0x10;
System.out.printf("%x\n", a << 1);
// 运行结果
20

右移 >>: 最右侧位不要了, 最左侧补符号位(正数补0, 负数补1)

int a = 0x10;
System.out.printf("%x\n", a >> 1);
// 运行结果(注意, 是按十六进制打印的)
8

无符号右移 >>>: 最右侧位不要了, 最左侧补 0

int a = 0xffffffff;
System.out.printf("%x\n", a >>> 1);
// 运行结果(注意, 是按十六进制打印的)
7fffffff

注意:
1. 左移 1 位, 相当于原数字 * 2. 左移 N 位, 相当于原数字 * 2 的N次方.
2. 右移 1 位, 相当于原数字 / 2. 右移 N 位, 相当于原数字 / 2 的N次方.
3. 由于计算机计算移位效率高于计算乘除, 当某个代码正好乘除 2 的N次方的时候可以用移位运算代替.
4. 移动负数位或者移位位数过大都没有意义

7. 条件运算符
条件运算符只有一个:
表达式1 ? 表达式2 : 表达式3
当 表达式1 的值为 true 时, 整个表达式的值为 表达式2 的值; 当 表达式1 的值为 false 时, 整个表达式的
值为 表达式3 的值.
也是 Java 中唯一的一个 三目运算符, 是条件判断语句的简化写法.

// 求两个整数的最大值
int a = 10;
int b = 20;
int max=a>b?a:b;

2.程序逻辑控制

1.顺序结构

顺序结构比较简单. 像我们之前写过的代码就是顺序结构的, 按照代码书写的顺序一行一行执行。

System.out.println("aaa");
System.out.println("bbb");
System.out.println("ccc");
// 运行结果
aaa
bbb
ccc
2.分支结构
2.1 if 语句

代码示例1: 判定一个数字是奇数还是偶数:

int num = 10;
if (num % 2 == 0) {
    System.out.println("num 是偶数");
} else {
    System.out.println("num 是奇数");
    }

代码示例2: 判定一个数字是正数还是负数:

int num = 10;
if (num > 0) {
    System.out.println("num 是正数");
} else if (num < 0) {
    System.out.println("num 是负数");
} else {
    System.out.println("num 是 0");
}

代码示例3: 判定某一年份是否是闰年:

int year = 2000;
if (year % 100 == 0) {
    // 判定世纪闰年
    if (year % 400 == 0) {
        System.out.println("是闰年");
   } else {
        System.out.println("不是闰年");
   }
} else {
    // 普通闰年
    if (year % 4 == 0) {
        System.out.println("是闰年");
   } else {
        System.out.println("不是闰年");
   }
}

注意事项1 悬垂 else 问题

int x = 10;
int y = 10;
if (x == 10) 
 if (y == 10)
 System.out.println("aaa");
else
 System.out.println("bbb");

if / else 语句中可以不加 大括号 . 但是也可以写语句(只能写一条语句). 此时 else 是和最接近的 if 匹配.
但是实际开发中我们 不建议 这么写. 最好加上大括号.

注意事项2 代码风格问题

// 风格1
int x = 10;
if (x == 10) {
    // 满足条件
} else {
    // 不满足条件
}
2.2 switch 语句

基本语法

switch(整数|枚举|字符|字符串){
 case 内容1 : {
 内容满足时执行语句;
 [break;]
 }
 case 内容2 : {
 内容满足时执行语句;
 [break;]
 }
 ...
 default:{
 内容都不满足时执行语句;
 [break;]
 } 
}

代码示例: 根据 day 的值输出星期:

int day = 1;
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("输入有误");
        break;
}

根据 switch 中值的不同, 会执行对应的 case 语句. 遇到 break 就会结束该 case 语句.
如果 switch 中的值没有匹配的 case, 就会执行 default 中的语句.
我们建议一个 switch 语句最好都要带上default.

3. 循环结构
3.1 while 循环

基本语法格式:

while(循环条件){
 循环语句;
 }

循环条件为 true, 则执行循环语句; 否则结束循环.

代码示例1: 打印 1 - 10 的数字:

int num = 1;
while (num <= 10) {
    System.out.println(num);
    num++;
}

代码示例2: 计算 1 - 100 的和

int n = 1;
int result = 0;
while (n <= 100) {
    result += n;
 n++;
}
System.out.println(num);
// 执行结果
5050
3.2 break

break 的功能是让循环提前结束.
代码示例: 找到 100 - 200 中第一个 3 的倍数:

int num = 100;
while (num <= 200) {
    if (num % 3 == 0) {
        System.out.println("找到了 3 的倍数, 为:" + num);
        break;
   }
    num++;
}
// 执行结果
找到了 3 的倍数,:102

执行到 break 就会让循环结束!!!

3.3 continue

continue 的功能是跳过这次循环, 立即进入下次循环
代码示例: 找到 100 - 200 中所有 3 的倍数

int num = 100;
while (num <= 200) {
    if (num % 3 != 0) {
        num++;  // 这里的 ++ 不要忘记! 否则会死循环. 
        continue;
   }
    System.out.println("找到了 3 的倍数, 为:" + num);
        num++;
        }

执行到 continue 语句的时候, 就会立刻进入下次循环(判定循环条件), 从而不会执行到下方的打印语句.

3.4 for 循环

基本语法

for(表达式1;表达式2;表达式3){
 循环体;
}

表达式1: 用于初始化循环变量.
表达式2: 循环条件
表达式3: 更新循环变量.
相比于 while 循环, for 循环将这三个部分合并在一起, 写代码时不容易遗漏。

代码示例1: 打印 1 - 10 的数字

for (int i = 1; i <= 10; i++) {
    System.out.println(i);
}
3.5 do while 循环

基本语法

do{
 循环语句;
}while(循环条件);

先执行循环语句, 再判定循环条件
代码示例: 打印 1 - 10

int num = 1;
do {
    System.out.println(num);
    num++;
} while (num <= 10);

注意事项

  1. do while 循环最后的分号不要忘记
  2. 一般 do while 很少用到, 更推荐使用 for 和 while.

3.方法的使用

Java语言中的“方法”(Method)在其他语言当中也可能被称为“函数”(Function)。对于一些复杂的代码逻辑,如果希望重复使用这些代码,并且做到“随时任意使用”,那么就可以将这些代码放在一个大括号“{}”当中,并且起一个名字。使用代码的时候,直接找到名字调用即可。

修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。 返回值类型
:方法可能会返回值。returnValueType
是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType 是关键字void。
方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
方法体:方法体包含具体的语句,定义该方法的功能。

1. 示例:计算 1! + 2! + 3! + 4! + 5!

1.1 不使用方法完成

public class Test {
    public static void main(String[] args) {
        int sum = 0;
        
        for (int i = 1; i <= 5; i++) {
            int tmp = 1;
            for (int j = 1; j <= i; j++) {
                tmp *= j;
           }
            sum += tmp;
       }
        
        System.out.println("sum = " + sum);
   }
}

1.2 使用方法完成

public class Test {
    public static int fac(int n) {
        int f = 1;
        
        for (int i = 1; i <= n; i++) {
            f *= i;
       }
        
        return f;
   }
    
    public static void main(String[] args) {
       int s = 0;
        
        for (int i = 1; i <= 5; i++) {
            s += fac(i);
       }
        
        System.out.println("sum = " + s);
        }
        }
2.方法的调用

方法的使用中,有以下几个重要的元素:

  1. 调用哪个方法。方法名称。
  2. 使用哪些具体的值,进行本次方法调用。调用时的实参(argument / actual parameter)。
  3. 调用方法后可能得到的返回值的后续处理。保存或者直接再次使用。

java 规定了方法定义的标准格式如下:

//不关心返回值
方法名称(实参列表);
// 将返回值保存到变量中
变量 = 方法名称(实参列表);
// 直接使用返回值参与运算
方法名称(实参列表) + 方法名称(实参列表);
3.重载

重载就是在一个类中,有相同的函数名称,但形参不同的函数。
方法重载的规则:方法名必须相同;参数列表必须不同(个数,类型,或参数顺序不同);方法的返回值可以相同也可以不相同;仅仅方 法返回类型不同不足以成为方法的重载。

实现理论:方法名相同时,编译器会根据调用方法的参数个数,参数类型等去逐个匹配,以选择对应的方法,若匹配失效,会报错。
代码示例:

package javaDailyProctice.ChongZai;

public class TestChong {
    public static void main(String[] args) {
        int a=10;
        int b=20;
        double c=10.0;
        double d=20.0;
        int result1=add(a,b);
        double result2=add(c,d);
        System.out.println(result1);
        System.out.println(result2);
    }

    public static int add(int i,int y) {
        return i+y;
    }
    public static double add(double i,double y){
        return i+y;
    }
}

运行结果:
在这里插入图片描述

4.数组的定义与使用

1.1 什么是数组

数组本质上就是让我们能 “批量” 创建相同类型的变量.

例如:
如果需要表示两个数据, 那么直接创建两个变量即可 int a; int b
如果需要表示五个数据, 那么可以创建五个变量 int a1; int a2; int a3; int a4; int a5;
但是如果需要表示一万个数据, 那么就不能创建一万个变量了. 这时候就需要使用数组, 帮我们批量
创建

1.2 创建数组

基本语法:

// 动态初始化
数据类型[] 数组名称 = new 数据类型 [] { 初始化数据 };
//静态初始化
数据类型[] 数组名称 ={ 初始化数据 };

代码示例:

int[] arr = new int[]{1, 2, 3};
int[] arr = {1, 2, 3};
1.3 数组的使用
int[] arr = {1, 2, 3};
// 获取数组长度
System.out.println("length: " + arr.length); // 执行结果: 3
// 访问数组中的元素
System.out.println(arr[1]); // 执行结果: 2
System.out.println(arr[0]); // 执行结果: 1
arr[2] = 100;
System.out.println(arr[2]); //执行结果:100

注意事项

  1. 使用 arr.length 能够获取到数组的长度. . 这个操作为成员访问操作符. 后面在面向对象中会经
    常用到.
  2. 使用 [ ] 按下标取数组元素. 需要注意, 下标从 0 开始计数
  3. 使用 [ ] 操作既能读取数据, 也能修改数据.
  4. 下标访问操作不能超出有效范围 [0, length - 1] , 如果超出有效范围, 会出现下标越界异常。
2. 数组作为方法的参数

2.1 基本用法
代码示例: 打印数组内容

public static void main(String[] args) {
    int[] arr = {1, 2, 3};
    printArray(arr);
}
public static void printArray(int[] a) {
    for (int x : a) {
        System.out.println(x);
   }
}
// 执行结果
1
2
3

3. 数组作为方法的返回值

代码示例: 写一个方法, 将数组中的每个元素都 * 2

// 返回一个新的数组
class Test {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3};
        int[] output = transform(arr);
        printArray(output);
   }
    public static void printArray(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
       }
   }
    public static int[] transform(int[] arr) {
        int[] ret = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            ret[i] = arr[i] * 2;
       }
        return ret;
   }
}
4. 二维数组

二维数组本质上也就是一维数组, 只不过每个元素又是一个一维数组.
基本语法:
数据类型[][] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };
代码示例:

int[][] arr = {
   {1, 2, 3, 4},
   {5, 6, 7, 8},
   {9, 10, 11, 12}
   };
   for (int row = 0; row < arr.length; row++) {
    for (int col = 0; col < arr[row].length; col++) {
        System.out.printf("%d\t", arr[row][col]);
   }
    System.out.println("");
}
// 执行结果
1       2       3       4
5       6       7       8
9       10      11      12

5.引用

1. 初步认识引用(reference)和对象(object)
String s = "Hello World"; // 这里的 s 的类型是 String 类型的引用;该引用指向了一个
String 类型的对象。
int[] a = { 1, 2, 3, 4, 5 }; // 这里的 a 的类型是 int[] 类型的引用;该引用指向了一个
元素类型是 int 的数组类型对象。
2. 理解引用和对象之间的关系

在这里插入图片描述

3. null 的理解
int[] a = null; // a 不指向任何的对象
4. 引用的赋值操作符理解
int[] a=null;
int[] b={1,2,3};
b=a;  让 b 指向 a 目前指向的对象
 // 由于 a 目前不指向任何的对象。所以 b 也不再指向任何的对象

总结:
1.引用是一种数据类型,用来指向对象。
2. 对引用进行的大部分操作实际上都是操作的该引用指向的对象。
3. 当多个引用指向同一个对象时,通过哪个引用修改了对象,其他引用都可以看到变化
4. 当一个引用不指向对象时,要求访问其指向的对象,就会遇到 NullPointerException。

6.类和对象

1. 什么是面相对象

Java是一门纯面相对象的语言(Object Oriented Program,继承OOP),在面相对象的世界里,一切皆为
对象。面相对象是解决问题的一种思想,主要依靠对象之间的交互完成一件事情。用面相对象的思想来
涉及程序,更符合人们对事物的认知,对于大型程序的设计、扩展以及维护都非常友好。

2. 类定义和使用
// 创建类
class ClassName{  
    field;//成员属性
    method;//成员方法
}

代码示例:

class Person {
    public int age;//成员属性  
    public String name;
    public String sex;
    public void eat() {//成员方法
       System.out.println("吃饭!");  
   }
    public void sleep() {
       System.out.println("睡觉!");  
   }
}
3. 类的实例化
3.1什么是实例化

定义了一个类,就相当于在计算机中定义了一种新的类型,与int,double类似,只不过int和double是
java语言自带的内置类型,而类是用户自定义了一个新的类型,比如上述的:Cat类和Computer类。有
了这些自定义的类之后,就可以使用这些类来定义实例(或者称为对象)。
用类类型创建对象的过程,称为类的实例化,在java中才用new关键字,配合类名来实例化对象。

class Person {
    public int age;//成员属性 实例变量
    public String name;
    public String sex;
    public void eat() {//成员方法
       System.out.println("吃饭!");  
   }
    public void sleep() {
       System.out.println("睡觉!");  
   }
}
public class Main{
 public static void main(String[] args) {
        Person person = new Person();//通过new实例化对象
        
        person.eat();//成员方法调用需要通过对象的引用调用
        person.sleep();
        
        //产生对象     实例化对象
        Person person2 = new Person();
        Person person3 = new Person();
 }
}

在这里插入图片描述

3.2 类和对象的说明
  1. 类只是一个模型一样的东西,用来对一个实体进行描述,限定了类有哪些成员.
  2. 类是一种自定义的类型,可以用来定义变量,但是在java中用类定义出来的变量我们成为对象.
  3. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
  4. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需
    要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储
    数据,占用物理空间
4.类的成员

类的成员可以包含以下:字段、方法、代码块、内部类和接口等;重点要掌握前三个。

4.1 字段/属性/成员变量

在类中, 但是方法外部定义的变量. 这样的变量我们称为 “字段” 或 “属性” 或 “成员变量”(三种称呼都可以,一般不会有严格的区分)
用于描述一个类中包含哪些数据:

class Person {
    public String name;// 字段
    public int age;
    }
class Test {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);
        System.out.println(person.age);
   }
}
// 执行结果
null
0
4.2方法 (method)

用于描述一个对象的行为:

class Person {
    public int age = 18;
    public String name = "张三";
    
    public void show() {
   System.out.println("我叫" + name + ", 今年" + age + "岁");
   }
}
class Test {
    public static void main(String[] args) {
        Person person = new Person();
        person.show();
   }
}
// 执行结果
我叫张三, 今年18
5.包

包 (package) 是组织类的一种方式,使用包的主要目的是保证类的唯一性。

5.1导入包中的类

Java 中已经提供了很多现成的类供我们使用. 例如:

public class Test {
    public static void main(String[] args) {
        java.util.Date date = new java.util.Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
   }
}

可以使用 java.util.Date 这种方式引入 java.util 这个包中的 Date 类。但是这种写法比较麻烦一些, 可以使用 import 语句导入包

import java.util.Date;
public class Test {
    public static void main(String[] args) {
        Date date = new Date();
        // 得到一个毫秒级别的时间戳
        System.out.println(date.getTime());
   }
}
5.2访问限定符

Java 中对于字段和方法共有四种访问权限
private: 类内部能访问, 类外部不能访问
默认(也叫包访问权限): 类内部能访问, 同一个包中的类可以访问, 其他类不能访问.
protected: 类内部能访问, 子类和同一个包中的类可以访问, 其他类不能访问.
public : 类内部和类的调用者都能访问
在这里插入图片描述

7.认识String类

可以参考下面这个链接,有详细介绍:
https://blog.csdn.net/m0_54798309/article/details/113267159?utm_source=app&app_version=4.5.4

8.面向对象编程

1. 继承

继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原
有类特 性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的
层次结构, 体现了由简单到复杂的认知过程。

1.1 语法规则
class 子类 extends 父类 {
    
}
1.2代码示例
package com.oop.Demo04;
public class Person {
    //public 公共的
    //protect 受保护的
    //default 默认的(不写)
    //private 私有的
    public int money = 100000;
    private int money1 = 100;
    public void say(){
        System.out.println("啊啊啊啊");
    }
    public int getMoney1() {
        return money1;
    }
    public void setMoney1(int money1) {
        this.money1 = money1;
    }
}
package com.oop.Demo04;
//子类继承父类就会拥有父类的所有方法
public class Student extends Person{
}

package com.oop.Demo04;
public class Application {
    public static void main(String[] args) {
   Student student = new Student();
   student.say();//调用父类方法
   student.getMoney1();//调用父类私有属性
        System.out.println(student.getMoney1());
    }
}

package com.oop.Demo05;
public class Person {
    public Person() {
        System.out.println("person无参执行了");
    }
    public void print(){
        System.out.println("Person");
    }
}

package com.oop.Demo05;
//子类继承父类就会拥有父类的所有方法
public class Student extends Person {
    public Student() {
        //默认调用父类的无参构造
        //super()调用父类的构造方法,必须在构造方法的第一个
        System.out.println("Student无参执行了");
    }
    public void print(){
        System.out.println("Student");
    }
    public void test1(){
        print();//Stdent
        this.print();//Student
        super.print();//Teacher
    }
}

package com.oop.Demo05;
public class Application {
    public static void main(String[] args) {
   Student student = new Student();
   //student.test1();
    }
}

** 总结:
1.super()调用父类的构造方法,必须在构造方法的第一个。
2.super必须只能出现在子类的方法或者构造方法中。
3.super和this不能同时调用构造方法。
4.this:本身调用者这个对象;super代表父类的对象 。
5.this在没有继承时也i可以使用,super只能在继承条件下才可以使用。
6.this():本类的构造;super():父类的构造。**

1.3重写

有继承关系,子类重写父类的方法,方法名相同方法体不同,非静态的方法才可以重写。

必要条件:方法名必须相同,参数列表必须相同,修饰符范围可以扩大不能缩小。抛出的异常范围可以被缩小不能被放大。

1.3.1静态方法
ackage com.oop.Demo06;
public class B {
    public  static void test(){
        System.out.println("B>>test()");
    }
}
ackage com.oop.Demo06;
public class A extends B{
    public static void test(){
        System.out.println("A>>test()");
    }
}
package com.oop.Demo06;
public class Application {
    public static void main(String[] args) {
        A a = new A();
        a.test();//A>>test()
        //父类的引用指向子类
        B b = new A();
        b.test();//B>>test()
    }
}

1.3.2非静态方法
package com.oop.Demo06;
public class B {
    public void test(){
        System.out.println("B>>test()");
    }
}
package com.oop.Demo06;
public class A extends B{
    //重写
    @Override  //注解 有功能的注释
    public void test(){
        System.out.println("A>>test()");
    }
}
package com.oop.Demo06;
public class Application {
    public static void main(String[] args) {
        //静态方法和非静态方法区别很大
        A a = new A();
        a.test();//A>>test()
        //父类的引用指向子类
        B b = new A();//子类重写了父类的方法
        b.test();//A>>test()
    }
}
2 组合

和继承类似, 组合也是一种表达类之间关系的方式, 也是能够达到代码重用的效果.
例如表示一个学校:

public class Student {
   ...
}
public class Teacher {
   ...
}
public class School {
    public Student[] students;
    public Teacher[] teachers;
}

组合并没有涉及到特殊的语法(诸如 extends 这样的关键字), 仅仅是将一个类的实例作为另外一个类的字
段.
这是我们设计类的一种常用方式之一.

组合表示 has - a 语义
在刚才的例子中, 我们可以理解成一个学校中 “包含” 若干学生和教师.
继承表示 is - a 语义
在上面的 “动物和猫” 的例子中, 我们可以理解成一只猫也 “是” 一种动物.
大家要注意体会两种语义的区别

3 多态
3.1 向上转型

代码示例:

package javaDailyProctice.ChongZai;
class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }
}

class Bird extends Animal{

    public Bird(String name) {
        super(name);
        System.out.println(name);
    }
}

public class MainTest {
    public static void main(String[] args) {
        Animal animal=new Bird("圆圆");
    }
}

此时animal 是一个父类 (Animal) 的引用, 指向一个子类 (Bird) 的实例. 这种写法称为 向上转型.

3.2动态绑定

代码示例:

// Animal.java
public class Animal {
    protected String name;
    public Animal(String name) {
        this.name = name;
   }
    public void eat(String food) {
        System.out.println("我是一只小动物");
        System.out.println(this.name + "正在吃" + food);
   }
}
// Bird.java
public class Bird extends Animal {
    public Bird(String name) {
        super(name);
          }
    public void eat(String food) {
        System.out.println("我是一只小鸟");
        System.out.println(this.name + "正在吃" + food);
   }
}
// Test.java
public class Test {
    public static void main(String[] args) {
        Animal animal1 = new Animal("圆圆");
        animal1.eat("谷子");
        Animal animal2 = new Bird("扁扁");
        animal2.eat("谷子");
   }
}
// 执行结果
我是一只小动物
圆圆正在吃谷子
我是一只小鸟
扁扁正在吃谷子

此时, 我们发现:
animal1 和 animal2 虽然都是 Animal 类型的引用, 但是animal1 指向 Animal 类型的实例,animal2 指向 Bird 类型的实例.针对 animal1 和 animal2 分别调用 eat 方法, 发现 animal1.eat() 实际调用了父类的方法, 而animal2.eat() 实际调用了子类的方法.
因此, 在 Java 中, 调用某个类的方法, 究竟执行了哪段代码 (是父类方法的代码还是子类方法的代码) , 要看究竟这个引用指向的是父类对象还是子类对象. 这个过程是程序运行时决定的(而不是编译期), 因此称为动态绑定.

3.3重载和重写的区别

在这里插入图片描述

3.4向下转型

向上转型是子类对象转成父类对象, 向下转型就是父类对象转成子类对象. 相比于向上转型来说, 向下转型没那么常见, 但是也有一定的用途。
代码示例:

// Animal.java
public class Animal {
    protected String name;
    public Animal(String name) {
        this.name = name;
   }
    public void eat(String food) {
        System.out.println("我是一只小动物");
        System.out.println(this.name + "正在吃" + food);
   }
}
// Bird.java
public class Bird extends Animal {
    public Bird(String name) {
        super(name);
   }
    public void eat(String food) {
        System.out.println("我是一只小鸟");
        System.out.println(this.name + "正在吃" + food);
   }
    
    public void fly() {
        System.out.println(this.name + "正在飞");
   }
}

接下来是我们熟悉的操作:

Animal animal = new Bird("圆圆");
animal.eat("谷子");
// 执行结果
圆圆正在吃谷子

接下来我们尝试让圆圆飞起来:

animal.fly();
// 编译出错
找不到 fly 方法

注意事项
编译过程中, animal 的类型是 Animal, 此时编译器只知道这个类中有一个 eat 方法, 没有 fly 方法.虽然 animal 实际引用的是一个 Bird 对象, 但是编译器是以 animal 的类型来查看有哪些方法的.对于 Animal animal = new Bird(“圆圆”) 这样的代码,编译器检查有哪些方法存在, 看的是 Animal 这个类型
执行时究竟执行父类的方法还是子类的方法, 看的是 Bird 这个类型.那么想实现刚才的效果, 就需要向下转型

// (Bird) 表示强制类型转换
Bird bird = (Bird)animal;
bird.fly();
// 执行结果
圆圆正在飞

但是这样的向下转型有时是不太可靠的. 例如:

Animal animal = new Cat("小猫");
Bird bird = (Bird)animal;
bird.fly();
// 执行结果, 抛出异常
Exception in thread "main" java.lang.ClassCastException: Cat cannot be cast to
Bird
 at Test.main(Test.java:35)

animal 本质上引用的是一个 Cat 对象, 是不能转成 Bird 对象的. 运行时就会抛出异常.所以, 为了让向下转型更安全, 我们可以先判定一下看看 animal 本质上是不是一个 Bird 实例, 再来转换

Animal animal = new Cat("小猫");
if (animal instanceof Bird) {
    Bird bird = (Bird)animal;
    bird.fly();
    }

instanceof 可以判定一个引用是否是某个类的实例. 如果是, 则返回 true. 这时再进行向下转型就比较
安全了.

3.5执行顺序

这个可以参考下面这个链接:
https://blog.csdn.net/m0_54798309/article/details/113094657?utm_source=app&app_version=4.5.4

9.认识异常

可以参考下面这个链接,有详细介绍:
https://blog.csdn.net/m0_54798309/article/details/113873274?utm_source=app&app_version=4.5.4

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值