写点什么

Java 难吗?Java 基础知识最强总结 (2021 版)

作者:XiaoLin_Java
  • 2021 年 12 月 01 日
  • 本文字数:8113 字

    阅读完需:约 27 分钟

Java难吗?Java基础知识最强总结(2021版)

一、Java

Java 诞生于 1995 年,原属于 SUN 公司,2009 年 4 月 20 日,美国数据软件巨头甲骨文公司(Oracle)宣布以 74 亿美元收购 SUN 公司。Java 是最受欢迎的开发语言,已经火了 20 年,并将继续引领着 IT 的编程语言。Java 的 LOGO 是一杯热气腾腾的咖啡,真的是令人回味无穷

1.1 为什么 Java 是平台无关性(可以跨平台)

传统语言



Java 语言



我们可以对 Java 程序进行编译操作,编译后生成一种和平台系统无关的文件——字节码文件(.class)。但是此时 Windows、Linux 均不能执行字节码文件,只有 Java 虚拟机(JVM)可以识别字节码文件,那么为了在 Windows 系统上运行该 Java 程序,我们就只能在 Windows 平台上安装 Windows 版本的 JVM,如果要在 Mac 系统上运行,那么得安装 Mac 版本的 JVM,总结来说就两点:


  1. Java 编译后生成和平台无关的.class 文件

  2. jvm 是平台相关的


在这里进行编译操作的工具叫做 javac,启动 JVM 并把字节码加载进 JVM 的工具叫做 java


二、Java 环境

2.1、JRE

JRE(Java Runtime Environment):Java 运行环境,如果要运行 Java 程序,就需要 JRE 的支持,JRE 里包含 JVM,一般在只运行程序而不开发程序的服务器中安装

2.2、JDK

JDK(Java Development Kit):Java 开发工具,包含开发 Java 程序的所有工具如 javac 和 java 等,JDK 包含 JRE,如果已经安装了 JDK 就不必安装 JRE

2.3、JVM

JVM(Java Virtual Machine):Java 虚拟机,它是运行所有 Java 程序的虚拟计算机。JVM 是不跨平台的,在 Windows 下装 Windows 版的 JVM,在 Linux 下装 Linux 版的 JVM

三、Java 编译和运行的机制


  1. 编写源文件(Java 文件)

  2. 使用 Java c 工具对源文件进行编译操作(java c 源文件.java),生成.class 文件

  3. 生成字节码文件(.class 文件)之后,使用 Java 工具启动 JVM,运行程序(java 主方法的类名)

四、Java 基础

4.1、语法规则

  1. Java 语言严格区分大小写,大写和小写是不同的概念

  2. 一个 Java 源文件里可以定义多个 Java 类,但其中最多只能有一个类被定义为 public 类,但如果源文件中包含了 public 类,源文件必须和 public 类同名

  3. 一个源文件中包含了 N 个 Java 类时,成功编译后会生成 N 份字节码文件,每一个类都会生成单独的.class 文件,且字节码的文件名和其对应的类名相同

  4. 若一个类想要运行,则必须拥有主方法(main),因为 main 方法是程序的入口

4.2、注释

Java 提供 3 种注释类型:


  1. 单行注释


//这是单行注释//快捷键:Ctrl+/
复制代码


  1. 多行注释


/*我是多行注释快捷键为:打/* 再按回车*/
复制代码


  1. 文档注释


     /*      *       * 我是文档类型      * 快捷键为:打/*然后按几下tab键      */
复制代码


多行注释之间彼此都不能交叉嵌套,因为/会找举例自己最近的/符号,组成一个注释语句块,上图中单独的*/符号就不能被编译器识别了

4.3、关键字和保留字

关键字


关键字:在编程语言中事先定义的,有着特殊含义和用途的单词


保留字


保留字:和关键字一样是编程语言事先定义好的,只是说现在暂时没有特殊的功能,但说不定以后某天会突然被赋予功能,因此被保留下来的单词。比如 goto 和 const 就是保留字

4.4、分隔符和标识符

4.4.1、分隔符

  1. 分号(;):语句的分割,表示一句话结束,好比咱们使用的句号。

  2. 花括号({}):表示一个代码块,是一个整体,花括号要成对使用。

  3. 方括号([]):定义数组和访问数组元素时使用。

  4. 圆括号(()):使用很广泛,具体用到细讲。

  5. 圆点(.):类和对象访问它的成员时使用。

  6. 空格( ):把一整条语句分割成几段,空格的次数不限制,好比一句英文里单词都要分开写一样。

4.4.2、标识符

在写代码的时候为了增强代码的阅读性,我们会自定义很多名字如:类名、方法名、变量名等。在编程的里,我们把这种为了增强程序阅读性而自定义的名称,称为标识符


标识符的命名规则:


  1. 由字母、数字、下划线、$组成,但不能以数字开头(注:此处的字母可以是中文、日文等)

  2. 大小写敏感

  3. 不能使用 Java 中的关键字和保留字

  4. 不能用 Java 中内置的类名

4.5、数据类型


注意:Java 只有 8 大数据类型,String 不属于基本数据类型,他属于引用数据类型


常用的整数类型是 int 和 long,byte 和 short 基本不用,常用的小数类型是 double,float 基本不用。因为 double 是不精确的,在实际开发中表示精确的小数我们使用 BigDecimal 类



  1. 整数类型默认是 int 类型,小数类型默认是 double 类型

  2. 表示 long 类型常量,要加 L 或者 l,建议加 L

  3. 表示 float 类型常量,要加 F 或者 f,建议加 F

五、变量

变量是内存中一块区域,可以往该区域存储数据,修改里面的数据,也可以获取里面的数据,一个变量如果没有被初始化,就意味着没有分配内存空间来存储,就不能使用


定义变量的语法格式如下:


  • String,表示类型,这里可以写任何的类型

  • name:变量名,和我们的姓名一样理解, 没有为什么

  • =:赋值运算符,后面会讲,意思是将右边的值赋值给左边的变量

  • “xiaolin”:一个字符串类型的值,如果是其他类型,不要加引号




变量的几个特点:


  1. 占据着内存中某一块存储区域

  2. 该区域有自己的变量名和数据类型

  3. 可以被重复使用

  4. 该区域的变量值可以在同一个类型的范围内不断地变化

5.1、变量的定义以及赋值

public class VarDemo{  public static void main(String[] args) {        // 方式一,先定义变量,再赋值    // 数据类型  变量名;如:int  age;    // 变量名 = 常量值;    // 定义一个int类型变量,初始值为17    int name;    //修改age变量的值为17    age = xiaolin;    System.out.println(age);        // 方式二,在声明时同时赋值(推荐)    // 数据类型 变量名 = 初始化值;          // 定义一个String类型的变量,初始值为zs        String name = "zs";  }}
复制代码


变量的使用注意如下几点:


  1. 变量必须是先声明再使用,并且初始化后才可以使用(定义包装类除外)

  2. 定义变量必须有数据类型

  3. 变量从开始定义到所在的作用域内可以使用,出了作用域之外就不可以使用了,且在同一作用域内,变量名不可以重复


常见的几种变量类型的定义:


public class VarDemo{
public static void main(String[] args) {
//byte类型变量 byte b = 20; System.out.println(b);
//short类型变量 short s = 20; System.out.println(s);
//int类型变量 int i = 20; System.out.println(i);
//long类型变量,使用L后缀 long l = 20L; System.out.println(l);
//float类型变量,使用F后缀 float f = 3.14F; System.out.println(f);
//double类型变量 double d = 3.14; System.out.println(d);
//char类型变量 char c = 'A'; System.out.println(c);
//boolean类型变量 boolean bb = true; System.out.println(bb);
//String类型变量 String str = "你好"; System.out.println(str); }}
复制代码

5.2、交换两个变量值

思路


  1. 把 num1 的值存储到临时变量 temp 中去

  2. 把 num2 的值赋给 num1 变量

  3. 把 temp 存储的值赋给 num2 变量



实现代码


public class ChangVarDemo{
public static void main(String[] args) { int num1 = 10; int num2 = 20; System.out.println("num1=" + num1); System.out.println("num2=" + num2); //-------------------------------- //交互操作 int temp = num1; num1 = num2; num2 = temp; //-------------------------------- System.out.println("num1=" + num1); System.out.println("num2=" + num2); }}
复制代码

六、表达式

表达式(expression),是由数字、运算符、括号、常量、变量等以能求得结果的组合


七、数据类型的转换

在 8 大基本数据类型中,boolean 不属于数值类型,所以不参与转换,其他类型的转换规则如下图。一般的,byte、short、char 三种类型相互之间一般不参与转换操作,按照转换方式,有两种(注意:boolean 类型不参与类型转换):


  1. 自动类型转换:范围小的数据类型直接转换成范围大的数据类型,小->大

  2. 强制类型转换:范围大的数据类型强制转换成范围小的数据类型,大->小

7.1、自动类型转换与提升

7.1.1、自动类型转换

自动类型转换,也称为“隐式类型转换,就是把范围小的数据类型直接转换成范围大的数据类型


转换规则:byte、short、char—>int—>long—>float—>double


注意事项:byte、short、char 相互之间不转换,他们参与运算首先转换为 int 类型


语法格式:范围大的数据类型 变量 = 范围小的数据类型值


public class TypeConvertDemo1{  public static void main(String[] args) {    //把int类型变量转为long类型    long longNumber = 17;//整数默认为int类型    //把long类型转换为float类型    float f1 = longNumber;    //把float类型转换为double类型    double d = f1;        //定义两个int类型的变量    int a1 = 2;    int b1 = 3;    int c1 = a1 + b1;
//定义一个byte类型,一个int类型 byte b2 = 2; int c2 = 3; System.out.println(b2 + c2);
//byte、short、char类型参与运算时把自己提升为int类型 //byte d1 = b2 + c2;//编译报错 int d3 = b2 + c2;//编译通过 }}
复制代码

7.1.2、自动类型提升

当一个算术表达式中,包含多个基本数据类型的常量或变量(boolean 除外)时,整个算术表达式的结果类型将出现自动提升,其规则是:


  • 所有的 byte、short、char 类型被自动提升到 int 类型,再参与运算

  • 整个表达式的最终结果类型,被提升到表达式中类型最高的类型


System.out.println('a' + 1);//98byte b = 22;b = b + 11;//编译出错,此时结果类型应该是intdouble d1 = 123 + 1.1F + 3.14 + 99L ;
复制代码


结论:算数表达式结果的类型就是其中范围最大的数据类型。

7.2、强制类型转换

强制类型转换,也称为“显式类型转换”,就是把范围大的数据类型强制转换成范围小的数据类型


# 语法格式:# 范围小的数据类型  变量 = (范围小的数据类型)范围大的数据类型值;
复制代码


注意:一般情况下不建议使用强转,因为强转有可能损失精度


public class TypeConvertDemo2{  public static void main(String[] args) {    int a = 2;    byte b = 3;    //自动类型转换    int c = a + b;    //强制类型转换    byte d = (byte) (a + b);    //把double转换为int类型    int i = (int)3.14;    System.out.println(i);//3  }}
复制代码

八、运算符

对常量和变量进行操作的符号称为运算符


常见的运算符分为:算术运算符、赋值运算符、比较运算符、逻辑运算符、三元运算符

8.1、算数运算符

8.2、自增和自减

自增:++,递增操作符,使变量值增加 1,有前置和后置之分,只能操作变量


自减:-- ,递减操作符,使变量值减去 1,有前置和后置之分,只能操作变量


以++为例:


a++和++a 结果都是让 a 的值自增 1,如果只是需要自增的话,使用哪一种都可以


但是他们俩有唯一的区别:


  1. 前置(++a): 表示对 a 加 1 之后的结果进行运算,先加后用

  2. 后置(a++):表示对 a 变量加 1 之前的值(原始值)进行运算,先用后加


public class ArithmeticOperatorsDemo2{  public static void main(String[] args) {    int a1 = 5;    int b1 = ++ a1;    System.out.println("a1=" + a1 + ",b1=" + b1);//a1=6,b1=6    int a2 = 5;    int b2 = a2 ++;    System.out.println("a2=" + a2 + ",b2=" + b2);//a2=6,b2=5  }}
复制代码


比较底层的解释


++a 表示取 a 的地址,增加它的内容,然后把值放在寄存器中 a++表示取 a 的地址,把它的值装入寄存器,然后增加内存中的 a 的值

8.3、赋值运算符

8.4、三元运算符

三元运算符,表示有三个元素参与的表达式,所以又称为三目运算符,其语义表示 if-else(如果什么情况就做什么,否则做什么)


语法格式:数据类型 变量 = boolean 表达式 ? 结果 A :结果 B


表达的意思,boolean 表达式结果:


  • 为 true,则三元运算符的结果是结果 A

  • 为 false,则三元运算符的结果是结果 B


注意:


  1. 三元运算符必须定义变量接受运算的结果,否则报错

  2. 三元运算符结果的类型由结果 A 和结果 B 来决定的,结果 A 和结果 B 的类型是相同的

8.5、逻辑运算符

逻辑运算符用于连接两个 boolean 表达式,结果也是 boolean 类型的



规律:


  • 非:取反,!true 则 false,!false 则 true

  • 与:有 false 则 false

  • 或:有 true 则 true

  • 异或:^ 相同则 false,不同则 true

8.5.1、&和 &&( | 和 | |)的区别

& :&左边表达式无论真假,&右边表达式都进行运算


&& :如果 &&左边表达式为真,&&右边表达式参与运算,否则 &&右边表达式不参与运算,故称短路与


| 和 || 的区别同理,||,左边为真,右边不参与运算


public class LogicalOperatorDemo2 {  public static void main(String[] args) {    System.out.println(false & 1 / 0 == 1);//报错,说明右边执行了    System.out.println(false && 1 / 0 == 1);//不报错,说明右边没有执行    System.out.println(true | 1 / 0 == 1);//报错,说明右边执行了    System.out.println(true | 1 / 0 == 1);//不报错,说明右边没有执行  }}
复制代码

九、数组

9.1、JVM 初探究


  • 程序计数器:当前线程所执行的字节码的行号的指示器

  • 本地方法栈:为虚拟机使用的 native 方法服务

  • 方法区:线程共享的内存区域,存储已经被虚拟机加载的类的信息、常量、静态变量,这个区域的内存回收的目标主要是针对常量池的回收和对类型的卸载

  • Java 虚拟机栈:简称栈,每个方法被执行的同时会创建一个栈帧用于存储该方法的局部变量、操作栈、动态链接、方法出口等信息

  • Java 堆:被所有线程共享的一块内存区域,在虚拟机创建的时候启动,所有对象的实例(new出来的对象)以及数组都要在堆上分配内存空间,所以堆占的内存空间远比栈大

  • 每当调用一个方法时,创建一个栈帧,存放了当前方法的局部变量,当方法调用完毕时,该方法的栈帧就被销毁了

  • 每次 new 一个对象的时候,就表示在内存中开辟了一块新的存储空间

9.2、数组

9.2.1、什么是数组

具有相同类型多个常量值有序组织起来的一种数据形式,数组中使用索引来表示元素存放的位置,索引从 0 开始步长是 1,有点像 Excel 表格的行号


9.2.2、定义语法

数组元素类型[]  数组名;int [] nums;
复制代码


注意:


  1. 可以把 int[] 看成一种数据类型,int 类型的数组类型

  2. int[]数组表示,这个数组中的元素都是 int 类型的,同理

9.2.3、数组的初始化

数组在定义后,必须初始化才能使用。所谓初始化,就是在堆内存中给数组分配存储空间,并为每一个元素赋上初始值,有两种方式:静态初始化和动态初始化数组的长度是固定的,无论以哪种,一旦初始化完成,数组的长度(元素的个数)就固定了,不能改变,除非重新对该初始化,初始化时,如果我们明确了具体的元素就用静态初始化,如果还不知道具体放哪些元素,只知道个数,用动态初始化

9.2.3.1、静态初始化

我们直接为每一个数组元素设置初始化值,而数组的长度由系统(JVM)决定


语法:数组元素类型[] 数组名 = new 数组元素类型[]{元素 1,元素 2,元素 3,.......};


int[] nums = new  int[]{1,3,5,7,9};//简单写法:int[] nums = {1,3,5,7,9};//简单写法,定义和初始化必须同时写出来
复制代码

9.2.3.2、静态初始化内存分析

public class ArrayDemo1{  public static void main(String[] args) {//定义并初始化数组    int[] nums = new int[] { 1, 3, 5, 7 };    System.out.println("数组长度=" + nums.length);//重新初始化数组    nums = new int[] { 2, 4, 8 };    System.out.println("数组长度=" + nums.length);  }}
复制代码



若 num = null,则 null 表示不再引用堆中的内存空间,那么此时 nums 就好比是没有初始化的,不能使用

9.2.3.4、动态初始化

程序员只设置数组元素个数,而数组的元素的初始值由系统(JVM)决定


语法:数组元素类型[] 数组名 = new 数组元素类型[length];int[] nums = new int[5];


注意:不能同时指定元素值和数组长度,int[] nums = new int[5]{1,3,5,7,9} 是错误的


内存图与静态初始化一样,只是拥有默认值

9.2.4、数组中对元素的操作

9.2.4.1、获取元素的个数

int size = 数组名.length;

9.2.4.2、设置元素

nums[1] = 30;

9.2.4.3、获取元素

元素类型 变量名 = 数组名[index];

9.2.5、数组中常见的异常

  1. NullPointerException:空指针异常(空引用异常)


操作了一个尚未初始化或者没有分配内存空间的数组


  1. ArrayIndexOutOfBoundsException:数组的索引越界异常


操作的数组的索引不在[0,数组名.length-1]范围内

9.2.6、数组遍历

9.2.6.1、for 循环

  int[] nums = new int[] { 1, 3, 5, 7 };for (int index = 0; index < nums.length; index++) {    int ele = nums[index];//index依次是 0、1、2、3    System.out.println(ele);    }
复制代码

9.2.6.2、for-each(增强 for 循环)

for(数组元素类型 变量: 数组){//TODO}
复制代码


int[] nums = new int[] { 1, 3, 5, 7 };for (int ele : nums) {System.out.println(ele);}
复制代码


使用 for-each 操作数组更简单,因为可以不关心索引,其底层原理依然是上述的 for 循环操作数组

9.2.7、二维数组

在之前,数组的每一个元素就是一个个的值,这种数组我们称之为一维数组。二维数组,就是数组中的每一个元素是另一个一维数组

9.2.7.1、二维数组的定义和初始化

静态


public class ArrayInArrayDemo1 {public static void main(String[] args) {//定义三个一维数组int[] arr1 = { 1, 2, 3 };int[] arr2 = { 4, 5 };int[] arr3 = { 6 };//把三个一维数组存储到另一个数组中,那么该数组就是二维数组int[][] arr = new int[][] { arr1, arr2, arr3 };}}
复制代码


二维数组中的元素类型是一维数组,把数组元素类型[]看成一个整体,表示数据类型


动态


数组元素类型[][] 数组名 = new 数组元素类型[x][y];x表示二维数组中有几个一维数组y表示每一个一维数组中有几个元素。int[][] arr = new int[3][5];
复制代码

9.2.7.2、获取二维数组的元素

for 循环


for (int index = 0; index < arr.length; index++) {//取出每一个一维数组int[] arr2= arr[index];//迭代一维数组for (int j = 0; j < arr2.length; j++) {int ele = arr2[j];System.out.println(ele);}System.out.println("-----");}
复制代码


for-each


for (int[] arr2 : arr) {  //arr2为每次遍历出来的一维数组for (int ele : arr2) {    //ele为从arr2一维数组中遍历出来的元素System.out.println(ele);}System.out.println("-----");}
复制代码

十、方法

10.1、方法的定义

方法:为了完成某一特定功能(如:求和,统计数量等)的代码块


语法格式:


修饰符] 返回值类型 方法名称(参数类型 参数名1,参数类型 参数名2,…){方法体;[return 返回值;]}
复制代码


格式分析:


  • 修饰符:public、static 等,static 修饰的方法直接使用类名调用即可,用 static 修饰的方法都属于类的

  • 返回值类型:限定返回值的类型,方法在完成一个功能后,是否需要给调用者返回一个结果?

  • 如果需要给调用者返回结果,就写上返回数据的类型

  • 如果不需要给调用者返回结果,就用关键字void,表示没有返回结果

  • 方法名称:用于调用方法,遵循标识符规范,首字母小写,采用驼峰命名法,见名知意

  • 形式参数:方法中圆括号中的变量,可以有多个形式参数

  • 方法体:编写如何完成该功能的代码

  • return 关键字的作用

  • 把返回值给方法的调用者

  • 结束该方法,在 return 后不可以再学任何语句

  • 当方法体中没有 return 时,方法的返回值类型必须为 void

  • 实际参数:在调用某一个具体方法 1 时,实际传递的参数值

  • 如果一个需要返回值,那么一定要保证在任何条件下都必须得有返回值


注意事项


  1. 方法必须定义到类中,在 java 中最小的程序单元是类

  2. 一个类中可以定义多个方法

  3. 方法和方法之间是平行的,不能在一个方法中定义另一个方法(相当于不可以在一个房子里面建房子)

  4. 方法定义没有先后顺序

10.2、方法的调用

如果方法有 static 修饰,可以直接用方法所在的类的类名调用,如果没有 static 修饰,那么必须使用实例化对象来调用

10.3、方法的重载

参数列表:参数的类型+参数的个数+参数的顺序


方法签名:方法名称+方法的参数列表


在同一个类中,方法签名是唯一的,否则编译报错


方法的重载:在同一个类中,允许某方法存在一个或者多个同名的方法,但是必须参数列表不同

10.3.1、如何是否是方法重载

方法重载判断的原则:两同一不同


两同:在同一个类中方法名相同


一不同:方法的参数列表不同(参数类型、参数个数、参数顺序),只要参数类型、参数个数、参数顺序其中有一个不同,都成为参数列表不同


方法的重载和返回值类型无关,只是一般都要求返回值类型相同

10.3.2、方法重载的作用

解决了同一功能的方法由于参数不同所造成的方法名称不同而需要重复命名的问题

发布于: 2021 年 12 月 01 日阅读数: 46
用户头像

XiaoLin_Java

关注

问啥啥都会,干啥啥不行。 2021.11.08 加入

问啥啥都会,干啥啥不行。CSDN原力作者,掘金优秀创作者。

评论

发布
暂无评论
Java难吗?Java基础知识最强总结(2021版)