Featured image of post java基础

java基础

本文阅读量

java学习

简介

Java是什么

人与人交流沟通的表达方式通过语言,那我们与计算机进行信息交流沟通通过什么语言呢? Java是一门优秀的计算机语言之一,还有其他优秀的计算机语言如:CC++GoPython等等。

Java之父:詹姆斯·高斯林(James Gosling)

java能做什么

java主要做企业服务器端软件的开发,占据90%以上的市场份额

服务端开发主要有以下几点:

  1. 数据响应
  2. 数据管理
  3. 业务分析
  4. 推荐算法
  5. 服务降级
  6. 集群脑裂
  7. 安全认证
  8. 权限管理
  9. 性能优化
  10. 事务管理

等等。

java平台分类

javaSE是java的核心和基础,是其他两个平台的基础,也可以开发桌面应用程序

javaEE,企业服务端开发的一套解决方案,可用于服务端应用开发

javaME,针对移动应用的解决方案,可开发小型或移动设备中的应用

jdk版本

我们必须安装JDK才能使用java,所谓的JDK(java development kit)就是java开发者工具包

jdk的重要历史版本如下:

  • 2014年JDK8(LTS)
  • 2018年9月JDK11(LTS)
  • 2021年9月JDK17(LTS)
  • 2023年9月JDK21(LTS)

注意:所谓的LTS就是长期支持版本(Long term support)

大部分企业为了系统的稳定,大部分选择的版本是JDK8,现在很多企业现在逐渐使用JDK11来进行开发了

jdk中的java与javac

java是执行工具,javac是编译工具

我们写的java程序是高级语言,计算机底层硬件是无法识别这些高级语言的,必须通过javac编译工具进行翻译,然后再通过java执行工具执行才能驱动机器干活

jdk组成

jdk主要由三部分构成:JVM,核心类库,开发工具

JVM:java虚拟机,真正运行java程序的地方,java是一门跨平台的语言,究其根本是java为每个平台构建了对应的JVM虚拟机

核心类库:java自己写好的程序,方便程序员调用的

其中JVM核心类库构成了java的运行环境(JRE)

基础语法

注释

注释是写在程序中,对代码进行解释说明的文字,主要为了方便自己和他人查看,以便理解程序的

分类

单行注释

1
// 单行注释内容

多行注释

1
2
3
4
5
/*
注释内容1
注释内容2
注释内容3
*/

文档注释

1
2
3
4
5
/**
注释内容1
注释内容2
注释内容3
*/

特点

注释不影响程序的执行(注释只作用在写代码阶段,编译后的class文件中已经没有注释了,所以注释不会影响程序的执行)

文档

我们可以根据文档注释来生成api文档,方便我们查阅

1
javadoc -d 文档生成目录 HelloWorld.java

这样就会根据HelloWorld中的文档注释将文档生成到指定目录中去了

数据类型

基本数据类型

基本数据类型分为4大类8种

1字节=8位 所以1byte占用数据类型最大值为1111 1111 = 256

整型

数据类型 内存占用(字节) 数据范围
byte 1 -128~127
short 2
int(默认) 4 大约21亿多
long 8 19位数
1
long lg = 2343453234232L;// long类型的数据必须在后面加上L/l

浮点型

数据类型 内存占用(字节) 数据范围
float 4
double(默认) 8
1
float ft = 3.14F; // float类型需要以f/F结尾

字符型

数据类型 内存占用(字节) 数据范围
char 2 0~65535

布尔型

数据类型 内存占用(字节) 数据范围
boolean 1 true,false

类型转换

自动类型转换

类型范围小的变量,可以直接赋值给类型范围大的变量

1
2
3
4
5
6
7
8
byte a = 12;
int b = a; // 自动类型转换


char ch = 'b';
int it = ch; // 自动类型转换
System.out.println(ch); // b
System.out.println(it); // 98

表达式的自动类型转换

在表达式中,小范围类型的变量,会自动转换成表达式中较大范围的类型,在参与运算

注意:

  1. 表达式的最终结果类型由表达式中的最高类型决定
  2. 在表达式中,byte、short、char是直接转换成int类型参与运算的
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
byte a = 10;
int b = 20;
long c = 30;
// int result = a + b + c; // 报错
long result = a + b + c;

// long result2 = a + b + 3.14; // 报错
double result2 = a + b + 3.14;


byte a1 = 10;
byte a2 = 20;
// byte a3 = a1 + a2; // 报错,因为,在表达式中,byte、short、char是`直接转换成int`类型参与运算的
int a3 = a1 + a2;

强制类型转换

大范围类型的变量 => 小范围类型的变量

1
2
3
4
5
6
7
8
数据类型 变量2 = (数据类型)变量1的数据
  
int a = 20;
byte b = (byte)a;


int i = 1500;
byte j = (byte)i; // Alt+enter, 强制类型转换可能出现数据溢出(失真)

浮点型强制转换成整型,直接丢掉小数部分,保留整数部分返回

引用数据类型

数组

变量

定义

就是给程序要处理的数据起一个名字,方便我们后期处理这个数据

声明

变量定义格式如下:

1
2
// 数据类型  变量名称  =  数据;
int age = 18;

注意

  1. 变量要先声明才能使用
  2. 变量是什么类型,就必须装载什么类型的数据
  3. 变量是从定义开始到“}”截止的范围内有效
  4. 同一范围内,变量的名称不能一样
  5. 变量定义的时候可以不赋初始值,但在使用时,变量里必须有值
  6. 变量存储在内存中的一块区域

关键字

java语言自己使用到的一些词汇,有特殊作用的,我们称之为关键字。

常见关键字如下:

public,class,int,double…..

标识符

标识符就是名字

基本要求

一般由数字、字母、下划线(_)和$符组成

强制要求

不能以数字开头,不能是关键字,不能包含一些特殊字符(&,%,#….)

建议

变量名:建议首字母小写,如:studyNumber

类名:建议首字母大写,如:HelloWorld

存储原理

计算机中表示数据的最小单位:1字节(byte:B)=8位(bit:b) 1B=8b

二进制

二进制转十进制:

在java中,二进制以0B0b开头

十进制

十进制转二进制,除二取余法

八进制/十六进制

为了便于观察和表示二进制,衍生出了八进制与十六进制

如:

1
2
3
// 十进制:97 对应的二进制: 01 100 001 对应的八进制就是:141
// 十进制:97 对应的二进制:0110 0001 对应的十六进制就是:61
// 十进制:250 对应的二进制:1111 1010 对应的十六进制就是:FA

在java中,八进制以0开头,十六进制以0X0x开头

字符存储

字符在底层存储的就是字符对应的ASCII的值

  • a => 97
  • A => 65
  • 0 => 48

图片存储

图片就是无数个像素点组成的,每个像素点的数据用0~255*255*255表示颜色

运算符

基本运算符

+,-,*,/,%

注意:

+符号与字符串运算的时候是用作连接符使用的,能算则算,不能算则连接在一起

1
2
3
4
5
int a = 5;
System.out.println("abc"+a); // abc5
System.out.println(a+5); // 10
System.out.println("abc"+a+'a'); // abc5a
System.out.println('a'+a+"abc"); // 102abc

自增自减运算符

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
int i = 10;
int rs = ++i; // ++/--在前,先自加后赋值
System.out.println(i); // 11
System.out.println(rs); // 11


int j = 10;
int rs2 = j++; // ++/--在后,先赋值后自加/自减
System.out.println(j); // 11
System.out.println(rs2); // 10

赋值运算符

+=,-=,*=,/=, %=

关系运算符

>,>=, <, <=,==,!=

逻辑运算符

符号 名称 运算逻辑
& 逻辑与 全为true,结果才为true
| 逻辑或 有一个为true,结果就为true
! 逻辑非
^ 逻辑异或 前后结果一致,返回false,前后结果不同,返回true
&& 短路与 左边只要出现false,右边就不执行
|| 短路或 左边只要出现true,右边就不执行

三元运算符

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

运算符优先级

流程控制

分支结构

if分支结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 单分支结构
if(){  
}
//
if(){  
}else{
}
// 多分支结构
if() { 
} else if() {
} else{
}

switch分支结构

通过比较值来决定执行哪条分支

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
switch(表达式){
  case 值1:
    执行代码1;
    break;
   case 值2:
    执行代码2;
    break;
   ...
   case 值n-1:
    执行代码n-1;
    break;  
  default:
    执行代码n;
}

执行流程

  1. 先执行表达式的值,再拿着这个值去与case后的值进行匹配
  2. 与哪个case后的值匹配为true,就执行哪个case块的代码,遇到break就跳出switch分支
  3. 如果全部case后的值与之匹配都是false,则执行default块的代码

注意事项

  1. 表达式类型只能是byte、short、int、char、jdk5开始支持枚举,jdk开始支持String、不支持double(计算机的二进制运算小数的方案本身就是不精确的)、float、long
  2. case给出的值不允许重复,且只能是字面量,不能是变量
  3. 正常使用switch的时候,不要忘记break,否则会出现穿透现象。

穿透现象不是一种bug,当存在多个case分支代码相同时,可以把相同的代码放到一个case块中,其他的case块都通过穿透性穿透到该case块执行代码即可,这样可以简化代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
switch(){
  case "1":
  case "2":
    代码;
    break;
  case 3:
    代码;
    break;
  default:
    代码;
    break;
}

循环结构

for循环结构

1
2
3
for(int i = 0;i<3;i++){
	System.out.println("hello world");
}

while循环结构

1
2
3
4
while(循环条件){
  循环体语句(被重复执行的代码);
  迭代语句;
}

我们知道循环几次:使用for,不知道循环几次:使用while

do while循环

特点:先执行后判断

1
2
3
4
do{
  循环体语句;
  迭代语句;
} while (循环条件);

死循环

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// for死循环
for(;;){
  System.out.println("hello world");
}
// while死循环
while(true){
  System.out.println("hello world");
}
// do-while死循环
do{
  System.out.println("hello world");
} while(true);

关键字

Break:跳出并结束当前所在循环的执行

continue:用于跳出当前循环的当次执行,直接进入循环的下一次执行

数组

数据就是一个容器,用来存一批同种类型的数据

定义

静态初始化数组

所谓静态数组就是:定义数组的时候直接给数组赋值

1
2
3
4
5
6
// 完整格式
int[] ages = new int[]{12,16,18};
// 简化格式
int[] ages = {12,16,18};
// 以上代码也可以这样写
int ages[] = {12,16,18};

动态初始化数组

定义数组时先不存入具体的元素值,只确定数组存储的数据类型和数组的长度

1
2
3
4
int[] arr = new int[3];
arr[0] = 12;
arr[1] = 16;
arr[2] = 18;

动态初始化数组元素默认值规则:

数据类型 明细 默认值
基本类型 byte,short,char,int,long 0
基本类型 float,double 0.0
基本类型 boolean false
引用类型 类、接口、数组、string null

数组在内存中执行过程

java内存分配:

  • 方法区(字节码文件加载到这里)

  • 栈内存(方法运行时所进入的内存,变量也在这里)

    特点:先进后出

  • 堆内存(new出来的东西会在这块内存中开盘空间并产生地址)

    特点:先进先出

注意

  1. 数组变量名中存储的是数组在内存中的地址,因此数组是一种引用数据类型
  2. 多变量指向同一个数组对象时,多变量修改的都是同一个数组对象中的数据,如果某个数组变量存储的的地址是null,那么该变量将不再指向任何数组对象(该变量没有指向数组对象),而不是将数组对象修改为null

方法

方法是一种用于执行特定任务或操作的代码块,就是一个功能的集合,它可以接收数据进行处理,并返回一个处理后的结果

定义

标准定义格式

1
2
3
4
修饰符 返回值类型 方法名(形参列表) {
  方法体代码(需要执行的功能代码)
    return 返回值;
}

执行原理

方法被调用的时候,是进入到栈内存中运行

为什么方法要放到栈中执行

我们知道栈的一个特点:先进后出

这样就有2个好处:

  1. 确保方法调用其他方法后可以回来
  2. 确保方法执行完毕后可以释放栈内存

参数传递

基本类型和引用类型的参数传递都是值传递,不同的是基本数据类型的参数传输的是存储的数据值的副本,而引用数据类型的参数传输存储的地址值

可变参数

就是一种特殊的形参,定义在方法、构造器的形参列表里,格式是:数据类型...参数名称

特点

可以不传数据给它,可以传一个或同时传多个数据给它,也可以传一个数组给它

1
2
3
4
5
6
7
8
9
public static void sum(int...nums){
  // 可变参数在方法内部本质就是一个数组
  System.out.println(Arrays.toString(nums));
}

sum();
sum(12);
sum(12,34,54,23);
sum(new int[]{12,34,54,23});

好处

常常用来灵活的接收数据

注意

  • 可变参数在形参列表中只能出现一个
  • 可变参数必须放到形参列表的 最后面
1
2
3
public static void sum(int...nums,int a){ // 错误,正确写法 int a,int...nums
  System.out.println(Arrays.toString(nums));
}

重载

一个类中,出现多个方法的名称相同,但是它们的形参列表是不同的,那么这些方法就称为方法重载了。

即:方法名称相同,形参不同(形参个数不同,形参类型不同,形参类型顺序不同)

注意

  1. 方法必须被调用才能执行
  2. 一个方法不能定义在另一个方法里
  3. 方法的返回值类型是void(无返回声明)时,方法内不能使用return返回数据
  4. return作用:立即跳出并结束当前方法的执行(语句的下面,不能编写代码,属于无效的代码,执行不到这儿),常用于卫语句拦截

包是分门别类管理程序的,类似于文件夹

建包语法

1
package com.snailsir.javabean;

注意事项

  1. 同一个包下的类,可以互相直接调用
  2. 如果调用其他包下的程序,则必须要导包,才可以访问!导包格式:import 包名.类名
  3. 如果调用的包名下的对象名重复,此时默认只能导入一个,另一个必须带包名访问

异常

程序可能出现的问题就是异常

常见异常

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
String name = null;
System.out.println(name.length()); // NullPointerException 空指针异常

System.out.println(10/0);// ArithmeticException 数学操作异常

Object o = "snailsir";
Integer i = (Integer)o; // ClassCastException 类型转换异常

String s = "23a";
int it = Integer.valueOf(s); // NumberFormatException 数字转换异常

异常体系

Java.lang.Throwable -> Error

​ -> Exception -> RuntimeExcetion -> …

​ -> 其他异常

Error:代表系统级错误(属于严重问题),我们开发人员不用管它。如:硬件内存不够

Exception:代表我们程序可能会出现的问题,因此,我们通常会用Exception以及它的子类来封装程序出现的问题

  • 运行时异常:RuntimeException及其子类,编译阶段不会出现错误提醒,运行时会出现的异常(如:数据索引越界异常)
  • 编译时异常:编译阶段就会出现错误提醒(如:日期解析异常)

编译异常处理2种方式

  1. 在方法上使用throws关键字,可以将方法内部出现的异常抛出去给调用者处理

    1
    2
    3
    
    方法 throws 异常1,异常2...{
      ....
    }
    
  2. 捕获异常(try…catch),直接捕获程序出现的异常

    1
    2
    3
    4
    5
    6
    7
    
    try{
      // 监视可能出现异常的代码
    }catch(异常类型1 变量){
      // 处理异常
    }catch(异常类型2 变量){
      // 处理异常
    }
    

作用

  1. 用来查询系统bug的关键参考信息
  2. 可以作为方法内部的一种特殊返回值,以便通知上层调用者底层的执行情况
1
2
3
4
5
6
7
8
public static int divide(int a,int b){
  if(b==0){
    System.out.println("参数有问题");
    // 代码有问题,我们就不能让代码继续往下执行了,我们应该怎么处理呢?这时候就需要我们抛出一个异常,作为返回值,通知上层,这里出现了bug
    throw new RuntimeException("/ by 0!");
  }
  return a/b;
}

异常处理

  1. 在最外层捕获异常,记录异常并响应合适的信息给用户

  2. 在最外层捕获异常,尝试重新修复

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    public static double getPrice(){
      Scanner sc = new Scanner(System.in);
      System.out.println("请输入一个价格:");
      return sc.nextDouble();
    }
    
    // 处理输入不合法的异常
    while(true){
      try{
        double price = getPrice();
        System.out.println("本商品价格:"+price);
        break;
      } catch(Exception e){
        System.out.println("您输入的价格不合法,请重新输入");
      }
    }
    

自定义异常

为了处理,java无法提供的因自己企业面临的问题,而出现的技术,我们就称之为自定义异常类。

自定义运行异常

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
//1、继承RuntimeExcepition
public class AgeIllegalRuntimeException extends RuntimeException{
  // 2、重写构造器
  public AgeIllegalRuntimeException(){}
  publci AgeIllegalRuntimeException(String message){
    super(message);
  }
}

// 使用自定义异常
public static void save(int age){
  if(age<=0 || age> 150){
    throw new AgeIllegalRuntimeException("年龄输入错误");
  }
  // 剩下代码
}

try{
  save(255);
}catch(Exception e){
  e.printStackTrace(); // 打印异常对象信息
}

自定义编译异常

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//1、继承Excepition
public class AgeIllegalRuntimeException extends Excepition{
  // 2、重写构造器
  public AgeIllegalRuntimeException(){}
  publci AgeIllegalRuntimeException(String message){
    super(message);
  }
}

// 使用自定义异常
public static void save(int age) throws AgeIllegalRuntimeException{
  // throw 方法内部使用,创建异常并从此抛出去
  // throws 方法上,抛出方法内部的异常给调用者
  if(age<=0 || age> 150){
    throw new  AgeIllegalRuntimeException("年龄输入错误");
  }
  // 剩下代码
}

try{
  save(255);
}catch(Exception e){
  e.printStackTrace(); // 打印异常对象信息
}

java在逐步抛弃编译异常(代码干扰太多),因此我们写异常尽量定义运行时异常

使用 Hugo 构建
主题 StackJimmy 设计