Java基础知识(入门篇)

707 阅读15分钟

第一章、Java入门

1、转义字符

  • \t :一个制表位,实现对齐的功能
  • \n :换行符
  • \\:一个\
  • \" :一个"
  • \' :一个'
  • \r :一个回车

练习:测试一下。

2、Java数据类型

分类:

image-20211022095944863

整数类型

image-20211022100617996

浮点类型

image-20211022100828954

说明

浮点数=符号位+指数位+尾数位。

浮点类型的尾数部分可能丢失,造成精度损失,比如:2.7 和 8.1 / 3是不一样的。

比如:

double num1 = 2.7;
double num2 = 8.1 / 3;
if(num1 == num2){
    System.out.println("二者相等");
}
//这句话是不会输出的

如果想让它能输出可以采用函数:

double num1 = 2.7;
double num2 = 8.1 / 3;
if(Math.abs(num1 - num2) < 0.00001){//这是判断二者相减的绝对值
    System.out.println("二者相等");
}

浮点类型也可以采用科学计数法的方式:5.12e2 = 5.12 × 10 ^ 2。

字符类型

允许写这种方式:

char c1 = 97;
char c2 = '\t';

java中char的本质就是一个整数,输出时输出的是它对应的编码。所以char类型是可以进行计算的。

字符类型存储到计算机的过程:

'a'--->字符编码是97--->二进制是1100001--->存储

从计算机读取的过程:

二进制1100001--->字符编码97--->'a'--->显示

布尔类型

boolean = true or false

布尔类型的值占用1个字节

3、字符集与字符编码(♥♥♥)

计算机中储存的信息都是用二进制数表示的;而我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果。通俗的说,按照何种规则将字符存储在计算机中,如'a'用什么表示,称为"编码";反之,将存储在计算机中的二进制数解析显示出来,称为"解码",如同密码学中的加密和解密。在解码过程中,如果使用了错误的解码规则,则导致'a'解析成'b'或者乱码。

  • ASCII字符编码:主要包括控制字符(回车键、退格、换行键等);可显示字符(英文大小写字符、阿拉伯数字和西文符号)。

    ASCII编码:将ASCII字符集转换为计算机可以接受的数字系统的数的规则。使用7位(bits)表示一个字符,共128字符;但是7位编码的字符集只能支持128个字符,为了表示更多的欧洲常用字符对ASCII进行了扩展,ASCII扩展字符集使用8位(bits)表示一个字符,共256字符。

  • Unicode字符编码:包含了非常多的字符,每个字符的编码都不同,所以不会有乱码问题。一个英文字母和汉字都占用2个字节,可能会存在冗余。

  • UTF-8字符编码:是一种针对Unicode的可变长度字符编码定长码),也是一种前缀码。它可以用来表示Unicode标准中的任何字符,且其编码中的第一个字节仍与ASCII兼容,现在使用最广泛。字母占1个字节,汉字占3个字节

4、数据类型转换

img

自动类型转换

image-20211022104611702

细节:

  • 多种类型数据计算的时候,会把它们先转换成类型最大的那个
  • (byte、short)和char之间不会进行自动类型转换
  • byte、short、char类型之间可以进行计算,但先要转成int类型
  • 自动提升原则:计算后,结果转成类型最大的那个

强制类型转换

将容量大的数据类型转换为容量小的数据类型。使用时要加上强制转换符 ( ),但可能造成 精度降低或溢出,格外要注意。

细节:

  • 强转符号只针对最近的操作数有效,所以一般会在后面数据操作加上括号
  • char类型可以保存int类型的值,但如果保存int类型的变量需要强转

数据类型和String类型转换

//基本类型转String
String s1 = 某基本数据类型的值 + "";

//String转基本数据类型,调用基本数据类型包装类.parse方法即可,如下:
int i1 = Integer.parseInt("123");

//注意String类型不能用这种方式转char类型,因为字符串包含多个字符,可以使用charAt方法
char c1 = s1.charAt(index);

5、运算符

运算符分类

  • 算术运算符
  • 赋值运算符
  • 关系运算符 [比较运算符]
  • 逻辑运算符
  • 位运算符 [需要二进制基础]
  • 三元运算符

算数运算符

image-20211022105731611

说明

除号/,如果10/3结果是整型不是浮点型

对一个数据取模,比如a % b,等同于a - a / b * b

或者可以这么认为,取模的符号和左边的数相互一致:

7 % 3 = 1;-7 % 3 = -1;7 % -3 = 1

经典习题

i = 10;
i = i++;
System.out.println(i);

赋值运算符

下面这些都是赋值运算符:

int a = 10;
a += 1;
a -= 1;

赋值运算符会进行类型转换:

byte a = 2;
a += 1;

//上面这个等价于 a = (byte)(a+1);

关系运算符

image-20211024181143573

关系运算符的结果都是boolean类型,要么是true,要么是false。

逻辑运算符

image-20211024181520138

逻辑与&,逻辑或|,逻辑异或^

短路与&&,短路或 ||,取反

短路&&,只要第一个为false那后面不判断,短路或||,只要后面有一个为true后面不判断。

public static void main(String[] args) {
    int x = 5;
    int y = 5;
    if (x++== 6 & ++y== 6){

    }
    System.out.println("x = " + x + " y = " + y);
}
//x = 6;y = 6
public static void main(String[] args) {
    int x = 5;
    int y = 5;
    if (x++== 6 && ++y== 6){

    }
    System.out.println("x = " + x + " y = " + y);
}
//x = 6;y = 5

三元运算符

条件表达式 ? 表达式 1: 表达式 2;

为true执行表达式1,false执行表达式2。

public static void main(String[] args) {
    int a = 10;
    int b = 99;
    int result = a > b ? a++ : b++;
    System.out.println("result=" + result);
    System.out.println("a=" + a);
    System.out.println("b=" + b);
}

题目:计算三个数中最大的那个

public static void main(String[] args) {
    int num1 = 270;
    int num2 = 25;
    int num3 = 104;
    int bigNum1 = num1 > num2 ? num1 :num2;
    int max = bigNum1 > num3 ? bigNum1 : num3;
    System.out.println("最大的数是:" + max);
    
    
    //或者
    int max = (num1 > num2 ? num1 : num2) > num3 ? (num1 > num2 ? num1 : num2) : num3;
    System.out.println("最大的数是:" + max);
}

位运算符

image-20211024182119514

算术右移 >>:低位溢出,符号位不变,并用符号位补溢出的高位

算术左移 <<: 符号位不变,低位补 0

逻辑右移 >>>:也叫无符号右移,运算规则是: 低位溢出,高位补 0

运算符的优先级

在这里插入图片描述

其中最需要注意的就是:逻辑与、逻辑或、逻辑非的优先级

逻辑非 > 逻辑与 > 逻辑或

//好好看这个例子
boolean s1 = true,s2 = true,s3 = false;
System.out.println(s1 || s2 && s3);//true

6、进制换算

常用的进制的符号:

  1. 十进制就是直接写即可
  2. 八进制要求以0开头,比如:015
  3. 十六进制:0x开头,比如:0x15
  4. 二进制:要求0b或0B开头,比如0b11011

其他细节:

  • 其他进制转换成十进制,按照每一位进行计算,最后一位是进制的0次方,依次往前算
  • 十进制转换成其他进制,拿这个数除以换算的进制,取余数并且反向输出即可
  • 二进制转八进制,每3位一组去计算即可
  • 二进制转十六进制,每4位一组去计算
  • 八进制转二进制:八进制每一位都换成二进制的三位
  • 十六进制转二进制:同上,变成一位变四位
image-20211024222228022

第二章、程序控制结构

1、顺序控制

就是按照程序代码的顺序执行。

2、分支控制(if)

分为以下:

if单分支、if-else双分支、if-else if...-else多分支、嵌套分支。

题目:判断一个年份是否是闰年,闰年的条件是符合下面二者之一:

​ (1)年份能被 4 整除,但不能被 100 整除;

​ (2)能被 400 整除

public static void main(String[] args) {
    int year = 2100;
    System.out.println(isRunNian(year) ? year + "是闰年" : year + "不是闰年");
}

public static boolean isRunNian(int year){
    if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0){
        return true;
    }else{
        return false;
    }
}

题目:下面这个输出什么?

public static void main(String[] args) {
    boolean b = true;
    if (b == false){	//这里输出b,如果把 b==false 改成 b=false 输出c
        System.out.println("a");
    }else if (b){
        System.out.println("b");
    }else if (!b){
        System.out.println("c");
    }else{
        System.out.println("d");
    }
}

题目:参加歌手比赛,如果初赛成绩大于 8.0 进入决赛,否则提示淘汰。并且根据性别提示进入男子组或女子组, 输入成绩和性别,进行判断和输出信息。

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    System.out.println("请输出选手的成绩");
    double score = scanner.nextDouble();
    if (score >= 8.0) {
        System.out.println("请输出选手的性别");
        char gender = scanner.next().charAt(0);
        if (gender == '男'){
            System.out.println("进入男子组");
        }else if (gender == '女'){
            System.out.println("进入女子组");
        }else {
            System.out.println("性别输入有误");
        }
    }else{
        System.out.println("你好,成绩不合格,你被淘汰了");
    }
}

3、分支控制(switch)

语法:

image-20211024224530547

流程图如下:

image-20211024224636152

如果case语句种没有break,那么就继续执行下一个case中的语句,这个叫做穿透

switch(表达式),表达式的返回值必须是byte、short、int、char、enums,String类型。

switch和if语句的区别?

  • 如果判断的具体数值不多,而且符合 byte、 short 、int、 char, enum[枚举], String 这 6 种类型。虽然两个语句都可以使用,建议使用 swtich 语句。

  • 其他情况:对区间判断,对结果为 boolean 类型判断,使用 if,if 的使用范围更广。

4、循环控制(for)

语法:

image-20211024225057183

细节:

  • for(;循环判断条件;) 中的初始化和变量迭代可以写到其它地方,但是两边的分号不能省略。
  • 循环初始值可以有多条初始化语句,但要求类型一样,并且中间用逗号隔开,循环变量迭代也可以有多条变量迭代语句,中间用逗号隔开。

5、循环控制(while)

语法:

image-20211024225300594

6、循环控制(dowhile)

语法:

循环变量初始化; 
do{ 
    循环体(语句); 
    循环变量迭代; 
}while(循环条件);

先执行一次再判断,固定至少执行一次

上面这些循环可以嵌套执行。

7、跳转控制(break、continue)

  • continue语句用于结束本次循环,继续执行下一次循环
  • continue 语句出现在多层嵌套的循环语句体中时,可以通过标签指明要跳过的是哪一层循环 , 这个和前面的标签的使用的规则一样.
  • break 语句用于终止某个语句块的执行,一般使用在 switch 或者循环[for , while , do-while]中

第三章、数组

1、一维数组简介

数组是一种引用类型的数据结构,可以储存同一种类型的数据。

动态初始化数组:

//声明数组
int a[]; 或者 int[] a
    
//创建数组
a=new int[10];

静态初始化数组:

int[] a = {1,4,5,1,5,2,7};

细节

  • 数组元素可以是引用类型,也可以是基本类型
  • 创建的数组如果没赋值,是有默认值的
  • 可能会报数组下标越界异常

练习:

  1. 创建一个 char 类型的 26 个元素的数组,分别 放置'A'-'Z'。使用 for 循环访问所有元素并打印出来。提示:char 类型数据运算 'A'+2 -> 'C'
  2. 请求出一个数组 int[]的最大值 {4,-1,9, 10,23},并得到对应的下标。

2、数组赋值机制和数组拷贝

数组在默认情况下是引用传递,赋的值是地址。

值传递/值拷贝 和 引用传递/引用拷贝的区别可以使用代码测试一下。

测试一下怎么让数组进行值拷贝。

3、数组反转

两种方式:

  • 找规律反转
  • 使用逆序赋值的方式

4、数组添加/扩容

练习1:实现动态的给数组添加元素效果,实现对数组扩容。ArrayAdd.java

  • 原始数组使用静态分配 int[] arr = {1,2,3}
  • 增加的元素 4,直接放在数组的最后 arr = {1,2,3,4}
  • 用户可以通过如下方法来决定是否继续添加,添加成功,是否继续?y/n

练习2:有一个数组 {1, 2, 3, 4, 5}, 可以将该数组进行缩减,提示用户是否继续缩减,每次缩减最后那个元素。当只剩下最后一个元素,提示,不能再缩减。

5、数组排序与查找

排序

冒泡排序法、选择排序法。

查找

二分查找

练习:有一个数列:白眉鹰王、金毛狮王、紫衫龙王、青翼蝠王猜数游戏:从键盘中任意输入一个名称,判断数列中是否包含此名称【顺序查找】 要求: 如果找到了,就提示找到,并给出下标值。

6、二维数组

动态初始化和静态初始化,方式同上。

动态初始化数组:

//声明数组
int a[][]; 或者 int[][] a
    
//创建数组
a=new int[10][5];

静态初始化数组:

int[][] a = {{},{},{},{}};

练习:使用二维数组打印一个 10 行杨辉三角。

细节:

1、二维数组的声明方式有: int[][] y 或者 int[] y[] 或者 int y[][]

2、二维数组实际上是由多个一维数组组成的,它的各个一维数组的长度可以相同,也可以不相同

第四章、面向对象(OOP)

1、对象

image-20211116083255685
  • 类是抽象的,概念的,代表一类事物,比如人类,猫类.., 即它是数据类型.
  • 对象是具体的,实际的,代表一个具体事物, 即 是实例.
  • 类是对象的模板,对象是类的一个个体,对应一个实例

对象创建在内存中是怎么存在的:

image-20211116083416950

在堆中开辟对象的内存空间,它的常量存储在方法区中,栈中存储存储这个对象的引用地址,这个变量名称指向堆中对象的内存地址。

对象的属性如果不赋值是有默认值的。

2、方法

方法在内存中的执行流程:

image-20211116084739968

方法的作用:

  • 提高代码的复用性
  • 可以将实现的细节封装起来,然后供其他用户来调用即可

方法语法:

访问修饰符 返回数据类型 方法名(形参列表..) {
    //方法体 语句; 
    return 返回值; 
}

方法的传参机制:

  • 基本数据类型传递的是值,值传递
  • 引用数据类型传递的是地址,引用的值就是地址

克隆对象自己实操一下。

3、递归

递归就是方法自己调用自己

练习:

1、阶乘问题

2、斐波那契数列

3、有一堆桃子,猴子每天吃掉一半还多一个,吃了10天,发现最后剩下1个桃子,问原来有多少?

4、迷宫问题

5、汉诺塔

6、八皇后问题

4、方法重载

要求:

  • 方法名相同
  • 形参列表不同:数量、类型、顺序不一样都算
  • 返回值无所谓

形参是可变参数的方法,语法如下:

访问修饰符 返回类型 方法名(数据类型... 形参名) { 
	//方法体;
}

可变参数可以是0-任意个,可变参数的实参可以是数组,而且本质也是个数组。

方法重载为什么不由返回值决定?

重载一般是编译阶段就已经确定好用哪个了,可是如果重载也可以由返回值决定,在程序都没运行完,怎么知道返回值是什么类型的呢?所以不成立,甚至有的方法都没有返回值,程序员本身某一行代码也不需拿到返回值,所以他就写了一行:

f();

谁知道这一行代码要调用的是有返回值的方法呢?还是void的方法呢?所以不能用返回值判断重载。

5、作用域

image-20211116090532880

6、变量和常量

  • 局部变量:不会赋初始值,作用域在方法里
  • 成员变量:会赋初始值,作用域在对象上
  • 静态变量:会赋初始值,作用域在类上
  • 常量:final修饰的变量

7、构造器

也叫构造方法:

【修饰符】 方法名(形参列表){
    方法体;
}

细节:

  • 构造器的修饰符可以是public / protected / private
  • 构造器没有返回值
  • 构造器调用是由系统完成的,new的时候使用的就是构造器
  • 构造器的作用是完成新对象的初始化,而不是对象的创建,这个时候对象的空间已经存在了,只是完成对象的初始化工作
  • 默认构造器是无参的,没写就给个无参的
class Dog{
    //这就是默认构造器
   	Dog(){
        
    }
}

可以使用反编译工具javap来查看:

javap <option> <class>
指令含义
-help --help -?输出此用法消息
-version版本信息
-v -verbose输出附加信息
-l输出行号和本地变量表
-public仅显示公共类和成员
-protected显示受保护的/公共类和成员
-package显示程序包/受保护的/公共类和成员 (默认)
-p -private显示所有类和成员
-c对代码进行反汇编
-s输出内部类型签名
-sysinfo显示正在处理的类的系统信息 (路径, 大小, 日期, MD5 散列)
-constants显示最终常量
-classpath指定查找用户类文件的位置

对象创建的流程:

  1. 加载类信息(Person.class)只加载一次
  2. 在堆空间分配空间(内存地址)
  3. 完成初始化对象(先进行默认初始化:赋默认值,然后显示初始化:赋自定义的值)
  4. 把堆中的地址返回给栈中的变量名(也就是让遥控器person,直接指向对象,以后可以由遥控器调用对象)

8、this

字符串常量池指向堆中

image-20211207152610067
  • this等于创建对象的时候,单独创建了一个空间指向了自己

  • this 关键字可以用来访问本类的属性、方法、构造器

  • 访问构造器语法:this(参数列表); 注意只能在构造器中使用(即只能在构造器中访问另外一个构造器, `必须放在第一

    条语句`)

public class ThisTest {
    public static void main(String[] args) {
        Boy boy = new Boy("张三",20);
        System.out.println("当前对象的哈希值:" + boy.hashCode());
    }
}

class Boy{
    String name;
    int age;

    public Boy(){

    }

    public Boy(String name,int age){
        //必须放在第一条语句
        this();
        this.name = name;
        this.age = age;
        System.out.println("this对象的哈希值:" + this.hashCode());
    }
}