Java基础总结

文章目录


前言

在假期期间把自己以前学过的内容简单总结一下,肯定有不足或者不正确的地方,如果正好有被大佬看见的话欢迎指正,多谢。
本文我有参考一位大佬的总结,有想学习Java的同学觉得我写的不好的话可以留下建议,然后去看那位大佬的总结,链接我放在下面。

Java2021 详细知识点汇总


以下是本篇文章正文内容。

1、Java简介

1.1、Java的三个版本

  • JavaSE(标准版) Java的核心和基础
  • JavaME(移动版) 移动端
  • JavaEE(企业版) 企业开发

1.2、Java的特点

  • 简单性
  • 面向对象
  • 分布性
  • 编译和解释性
  • 稳健性
  • 安全性
  • 可移植性
  • 高性能
  • 多线程性
  • 动态性

2、Java的安装和配置

2.1、安装jdk

jdk下载网址

我们一般使用jdk8,下载Windows x 64 版本安装即可。
jdk:开发者工具包。
jre:运行环境。

jdk目录结构

jdk目录结构

目录目录说明
bin存放开发Java程序的工具,例如:编译工具(javac.exe)、运行工具 (java.exe) 、打包工具 (jar.exe)等。
db纯Java编写的数据库Derby。
includeC语言头文件,用于支持Java程序设计。
jreJava运行环境根目录。
jre\bin包含Java平台所使用工具和类库的可执行文件和DLL文件。
jre\libJava运行时使用的核心类库。
lib开发Java程序使用的类库文件。
src.zipJava的源代码包。

2.2、配置环境变量

安装完jdk后想要让操作系统可以找到Java并调用bin目录下的开发工具就需要配置环境变量。

  1. 选择系统变量,新建变量名为JAVA_HOME,值为JDK的安装目录。
    在这里插入图片描述
  2. 选择系统变量里的Path,给Path加入jdk下的bin目录。
    在这里插入图片描述
  3. 测试Java是否安装成功:在命令行界面输入 java -version 查看版本号。在这里插入图片描述

2.3、Java程序编译过程

  1. 源文件(xxx.java)通过 javac命令 编译为字节码(xxx.class 文件)
  2. 字节码再通过 java命令 交给JVM即Java虚拟机运行
  3. JVM把字节码翻译为机器码,最后由操作系统执行

ps:Java程序编译过程很复杂,有想要深入了解的同学可以自行查找资料。

2.4、Java开发工具

  • Eclipse
  • IDEA

3、基础语法

3.1、注释

  • 单行注释
    //单行注释

  • 多行注释
    /*
    多行注释
    */

  • 文档注释
    /**
    文档注释
    */

3.2、标识符

标识符概念

在计算机编程语言中,标识符是用户编程时使用的名字,用于给变量、常量、函数、语句块等命名,以建立起名称与使用之间的关系。标识符通常由字母和数字以及其它字符构成。

标识符的命名规则

  • 标识符由字母、数字、下划线“_”、汉字、美元符号“$”组成,第一个字符不能是数字。
  • 不能把java关键字和保留字作为标识符。
  • 标识符没有长度限制。
  • 标识符对大小写敏感。
    以下是Java的关键字和保留字
    Java关键字
    Java关键字含义

标识符的命名规范

  • 见名知义,需要由有意义的英文单词。
  • 变量名和方法名,驼峰命名,由一个或多个单词组成,第一个单词的开头小写后面的单词开头大写,如:goodsPrice、person。
  • 类名,类似驼峰命名,每个单词的开头都是大写,如:HelloWorld、MyFirstHomework。
  • 包名:全部单词小写中间由.连接,域名.公司名.项目名.模块名,如:com.sun.oa.login。
  • 常量名,全部单词大写,中间由下划线分隔,如:MAX_VALUE。

3.3、数据类型

基本数据类型

一共分4类,共8种

  • 整数:byte、short、int(默认值)、long
  • 浮点数:float、double(默认值)
  • 字符:char
  • 布尔值:boolean
数据类型字节长度取值范围
byte1字节-128 ~ 127
short2字节-2^15 ~ 2^15-1
int4字节-2^31 ~ 2^31-1
long8字节-2^63 ~ 2^63-1
float4字节-2^128 ~ 2^128
double8字节-2^1024 ~ 2^1024
char2字节0 ~ 2^16-1,ASCII代码,’A’对于65,‘a’对应97
boolean1位(1字节(byte)=8位(bit))true/false

注意:

  1. long类型变量赋值时,数字后面要加L或l,推荐使用L,用于区分1和l
    long num = 100L;
  2. float类型变量赋值时,浮点数后要添加f或F,否则默认是double类型,赋值出错
    float num = 10.5f;
  3. char的值用单引号括起来
    char c = ‘A’;

引用数据类型

类、接口、数组

简单讲,所有非基本类型都是引用数据类型。

3.4、类型转换

自动类型转换

低转高,编译器自动完成

强制类型转换

高转低,需要手动完成

数据类型 变量名 = (数据类型);
long a = 10;
int b = (int) a;

注意:

  1. 强制转换可能会丢失精度
  2. 类型转换都会影响程序的性能

3.5、变量和常量

变量

变量的三要素:

  1. 数据类型
  2. 变量名
  3. 初始值

定义变量的方法

  1. 定义变量,同时初始化
    数据类型 变量名 = 初始值;
    int hp = 100;
  2. 先定义变量,然后再初始化
    数据类型 变量名;
    变量名 = 值;
    int hp;
    hp = 100;
  3. 同时定义多个类型相同的变量
    数据类型 变量名1 = 值,变量名2 = 值;
    int hp = 100,mp = 300;

变量的作用域

  • 类变量:也叫静态变量,即变量前加了static的变量。
  • 实例变量:也叫对象变量,即没加static的变量。
  • 局部变量:定义在方法体内的变量。

常量

final关键字;
全部单词大写,中间由下划线分隔,如:MAX_VALUE。

3.6、运算符

算术运算符+,-,*,/,%,++,- -
赋值运算符=,+=,-=,*=,/=,%=
关系运算符>,<,>=,<=,==,!=
逻辑运算符&&,//,!
位运算符&按位与,/按位或,^按位异或,~取反,<<左移,>>右移
条件运算符?:

注意:
1、a++与++a不同之处,a–与--a同理

  • a++先进行其他运算再自增
  • ++a先自增再进行其他运算

2、==和=的区别

  • ==是比较两个值是否相等,=是进行赋值

3、与或非优先级

  • ! > && > ||

4、断路功能

  • 表达式1 && 表达式2
    表达式1为false,表达式2不会执行
  • 表达式1 || 表达式2
    表达式1为true,表达式2不会执行

5、条件运算符

  • 数据类型 变量名 = 条件 ? 值1 : 值2;
    可以用于条件判断,条件为true,返回值1,条件为false,返回值2。

运算符优先级

优先级由高到低:

  • () 小括号
  • ++、–、! 一元运算符
  • *、/、% 乘除取余算术运算符
  • +、- 加减
  • <、>、>=、<=、==、!= 关系运算符
  • && 逻辑运算符 与
  • || 或
  • ?: 条件运算符
  • =,+=,-=,*=,/=,%= 赋值运算符

3.7、包机制

  • 域名倒写:com.baidu.xxx
  • 防止命名冲突
  • package:如果有必须写在代码的第一行
  • import

3.8、javadoc

用于生成帮助文档

  • @author
  • @version
  • @pram
  • @since
  • @return
  • @thorws

4、流程控制

4.1、scanner

从键盘输入值给变量赋值,需要用到Scanner类(扫描器)

import java.util.Scanner;

//scanner类
public class demo03 {
    public static void main(String[] args) {
        //创建scanner类
        Scanner input = new Scanner(System.in);
        //输入
        String a = input.next();
        int b = input.nextInt();
        //输出
        System.out.println("输入的字符串是:"+a);
        System.out.println("输入的整数是:"+b);
    }
}

4.2、顺序结构

顺序结构是最简单的程序结构,也是最常用的程序结构,只要按照解决问题的顺序写出相应的语句就行,它的执行顺序是自上而下,依次执行。

4.3、选择结构

if语句

if(条件){
    语句;
}

if-else语句

if(条件){
    语句1;
}else{
    语句2;
}

多重if语句

if(条件1){
	语句1}else if(条件2){
	语句2}else{
	缺省语句;
}

嵌套if语句

if(外部条件){
	if(内部条件){
		语句;
	}else{
		语句;
	}
}else{
	语句;
}

switch结构

switch(表达式或变量){
	case1:
		语句1;
	break;
	case2:
		语句2;
	break;
	....
	default:
		缺省语句;
}

执行流程:

  • 首先用switch后面的表达式的值和case后面的值进行比较,若和值1相等则执行语句1,不相等就与case2值进行比较,若相等则执行语句2。
  • 以此类推,如果到default之前没有相等的情况则执行default中的语句结束。

注意事项:

  • 本身可以跟的类型:int,byte,short,char
    JDK5以后可以跟枚举类型
    JDK7以后可以跟String类型
  • case后面只能跟常量,不能跟变量且不能重复。
  • default可以在switch语句的任何位置,也可以省略不写。
  • 切记在case语句中缺少break会出现case穿透现象。
  • switch语句遇见break结束,或者程序默认执行到末尾结束。

switch与多重if的比较:

  • switch的运行流程和多重if一样,switch语法更加简洁。
  • switch只能用于判断单个值的,多重if可以判断一个范围。

case穿透现象:

//case穿透
public class demo04 {
    public static void main(String[] args) {
        int i = 1;
        switch (i){
            case 1:
                System.out.println(1);
            case 2:
                System.out.println(2);
                break;
            case 3:
                System.out.println(3);
                break;
            case 4:
                System.out.println(4);
                break;
            default:
                System.out.println("default");
                break;
            case 5:
                System.out.println(5);
                break;
        }
    }
}

输出结果:执行了case1后由于没有break语句导致继续执行下一条case2语句,然后遇到case2中的break语句后程序结束输出1和2,正常情况应该是只输出1。

4.4、循环结构

循环三要素

  1. 起始量,循环变量的初始化
  2. 停止循环的条件
  3. 循环变量的更新

for循环

一般用于固定次数的循环

for(循环变量的初始化;循环的条件;循环变量的更新){
	循环的执行语句;
}

执行流程:

  1. 初始化
  2. 判断循环条件,如果成立
  3. 执行循环语句
  4. 循环变量的更新
  5. 判断循环条件,如果成立

增强for循环

for each 的用法:

for(元素类型type 元素变量x : 遍历对象obj){
	引用了x的java语句;
}

总结:

  • for each是for循环在特殊情况下的增强版本。
  • 简化了编程,提高了代码的可读性和安全性(不用怕数组越界)。
  • 遍历数组和集合的时候建议使用for each。
  • 需要引用数组和集合的索引时for each无法做到。

while循环

循环变量的初始化
while(循环条件){
	循环的执行语句
	循环变量的更新
}

while循环执行的流程和for一样

do-while循环

变量的初始化;
do{
	循环执行的语句;
	变量的更新;
}while(循环条件);

do-while和for、while的区别:

  • for、while是先进行条件判断,再执行循环语句,如果条件不成立,一次都不执行。
  • do-while是先执行循环语句,再进行条件判断,如果条件不成立,至少会执行一次。

break关键字

break作用:在循环中间停止整个循环的执行。

//break关键字
public class demo05 {
    public static void main(String[] args) {
        //使用循环模拟上365天班
        for(int i = 1;i <= 365;i++){
            System.out.println("上了"+i+"天班");
            //在第100天中奖,辞职不上班了
            if(i == 100){
                //停止整个循环的执行
                break;
            }
        }
    }
}

continue关键字

continue作用:在循环中间跳过某一次循环的执行,继续下一次循环。

//continue关键字
public class demo06 {
    public static void main(String[] args) {
        for(int i = 1;i <= 356;i++){
            //在第100天,跳过当天的上班
            if(i == 100){
                System.out.println("今天发烧了,要请假!");
                //跳过本次循环,继续
                continue;
            }
            System.out.println("上第"+i+"天班");
        }
    }
}

嵌套循环

循环内部可以执行任何语句,包括另一个循环,这样就形成了嵌套循环。
如:

for(...){
    for(...){
        ...
    }
}
while(..){
    while(..){
        ...
    }
}

等,for、while、do-while也可以相互嵌套。

嵌套循环的执行流程:
外部循环执行一次,内部循环执行一轮。

九九乘法表:

//九九乘法表
public class demo07 {
    public static void main(String[] args) {
        for (int i = 1; i < 10; i++) {
            for (int j = 1; j <= i; j++) {
                System.out.print(j+"*"+i+"="+(j*i)+"\t");
            }
            System.out.println();
        }
    }
}

嵌套循环的break和continue

for(...){
    for(...){
     	if(...){
        	break/continue;
        }
    }
}

内层循环中的break和continue只对内层循环起作用,对外层没有影响。
如果希望break和continue影响外层循环,可以使用label标签(label标签可以自定义)

label:
for(...){
    for(...){
        if(...){
       		 break label;
        }
    }
}

以下是两个示例:

//break label
public class demo09 {
    public static void main(String[] args) {
        System.out.println("label test");
        outer:
        for (int i = 0; i < 3; i++) {
            System.out.println("outer" + i);
            inner:
            for (int j = 0; j < 3; j++) {
                System.out.println("inner" + j);
                break outer;
            }
        }
    }
}
//运行结果
//label test
//outer0
//inner0
//continue label
public class demo10 {
    public static void main(String[] args) {
        System.out.println("label test");
        outer:
        for (int i = 0; i < 3; i++) {
            System.out.println("outer" + i);
            inner:
            for (int j = 0; j < 3; j++) {
                System.out.println("inner" + j);
                continue outer;
            }
        }
    }
}
//运行结果
//label test
//outer0
//inner0
//outer1
//inner0
//outer2
//inner0

5、方法

5.1、方法的概述

什么是方法?

方法Method是一段代码块,当需要时可以被调用执行,在一些其他语言(C、JavaScript等)中又称为函数Function。

方法的好处

  1. 方法将代码进行封装,方便进行调用
  2. 代码可以被重用
  3. 代码方便进行维护

5.2、方法的定义

无参方法

public static 返回值类型 方法名(){
	方法体;
}

注意:如果没有返回值,返回值类型就为void(空)

有参方法

public static 返回值类型 方法名(数据类型 参数名,数据类型 参数名..){
	方法体;
}

注意:

  1. 参数可以没有,也可以有任意个,每个参数用逗号隔开。
  2. 形式参数由数据类型和参数名组成。
  3. 参数名不能重复。
  4. 定义方法时声明的参数叫形参(形式参数)。
  5. 调用方法时传入的参数叫实参(实际参数)。
  6. 一旦定义了形参,调用时必须传入对应类型和数量的实参。

5.3、方法的调用

类名.方法();
对象.方法();//对象就是平时我们new出来的东西
//调用有参方法需要传参

5.4、方法的重载

  1. 方法名相同
  2. 参数不同(类型,个数)

5.5、命令行传参

为了给main方法传递参数,进行JVM性能调优。

5.6、可变长参数

… 必须放在参数的末尾,否则会报错。

5.7、递归

自己调用自己,给自己一个出口

6、数组

6.1、数组的定义

创建数组时,同时定义数组的长度

类型[] 数组名 = new 类型[长度];
int[] array = new int[5];

[ ]也可以在数组名的后面

类型 数组名[] = new 类型[长度];
int array[] = new int[5];

也可以先声明数组,然后定义长度

类型[] 数组名;
数组名 = new 类型[长度];

注意:创建数组后,数据会有默认值:
int默认是0,float默认是0.0f,double默认是0.0,String默认是null。

6.2、数组的初始化

静态初始化

在定义数组的同时,给数组的数据赋值

数据类型[] 数组名 = {1,2,3...};
如:int[] array = {20,44,33,100,55};
数据类型[] 数组名 = new int[]{1,2,3...};
如:int[] array = new int[]{20,44,33,100,55};

注意:静态初始化就不能定义长度,数组的长度是由值的个数决定。

动态初始化

定义数组后,使用循环给数组赋值

int[] array = new int[5];
for(int i = 0;i < array.length;i++){
	array[i] = i;
}

数组的访问

数组通过 数组名[下标] 访问数据,注意:

  • 下标从0开始
  • 如果下标不在0到数组长度-1范围内,就会出现ArrayIndexOutOfBoundsException 异常(数组下标越界)

增强型的for循环

foreach循环是在jdk1.5后支持的语法,用于遍历数组或集合。

for(元素类型type 元素变量x : 遍历对象obj){
	引用了x的java语句;
}

6.3、二维数组

二维数组的定义

数据类型[][]  数组名 = new 数据类型[行数][列数];
int[][]	array = new int[3][5];

二维数组的访问

数组名[行下标][列下标];
访问上面数组第二行第三个元素,array[1][2];

二维数组的静态初始化

数据类型[][] 数组名 = {{,,...},{,,...},{,,...}..};
数据类型[][] 数组名 = new 数据类型[][]{{,,...},{,,...},{,,...}..};

二维数组的动态初始化

int[][]	array = new int[3][5];

6.4、Arrays工具类

  1. 排序
    Arrays.sort(数组名)
  2. 查找
    int Arrays.binarySearch(数组名,要找的数)
    获得的结果是要找数字的下标
  3. 复制
    Arrays.copyOf(被复制的数组名,新的数组的长度)
    获得的结果是新数组
  4. 填充
    Arrays.fill(数组名,要填充的数);
    给数组填充相同的值
  5. 比较
    Arrays.equals(数组名1, 数组名2)
    返回两个数组值是否相同
  6. 输出数组内容
    Arrays.toString(数组名)

6.5、排序算法

十大经典排序算法

冒泡排序

算法步骤:

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
  2. 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  3. 针对所有的元素重复以上的步骤,除了最后一个。
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
import java.util.Arrays;

//冒泡排序
public class BubbleSort {
    public static void main(String[] args) {
        int[] array = {25,15,30,50,45};
        //i控制比较次数
        for (int i = 0; i < array.length-1; i++) {
            //j控制前后两个比较的数字
            for (int j=0; j < array.length-i-1; j++){
                if (array[j] > array[j+1]){
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1]=tmp;
                }
            }
        }
        System.out.println(Arrays.toString(array));
    }
}

选择排序

算法步骤:

  1. 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
  2. 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
  3. 重复第二步,直到所有元素均排序完毕。
import java.util.Arrays;

//选择排序
public class SelectionSort {
    public static void main(String[] args) {
        int[] array = {25,15,30,50,45};
        //i控制比较次数
        for (int i = 0; i < array.length-1; i++) {
            int min = i;
            //j控制前后两个比较的数字来寻找最小的数字
            for (int j = i+1; j < array.length; j++) {
                if (array[j] < array[min]) {
                    // 记录目前能找到的最小值元素的下标
                    min = j;
                }
            }
            if(i != min){
                int tmp = array[i];
                array[i] = array[min];
                array[min] = tmp;
            }
        }
        System.out.println(Arrays.toString(array));
    }
}

插入排序

算法步骤:

  1. 将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
  2. 从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
//插入排序
public class InsertSort {
    public static void main(String[] args) {
        int[] array = {25,15,30,50,45};
        // 从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的
        for (int i = 1; i < array.length; i++) {
            // 记录要插入的数据
            int tmp = array[i];
            // 从已经排序的序列最右边的开始比较,找到比其小的数
            int j = i;
            while (j > 0 && tmp < array[j - 1]) {
                array[j] = array[j - 1];
                j--;
            }
            // 存在比其小的数,插入
            if (j != i) {
                array[j] = tmp;
            }
        }
        System.out.println(Arrays.toString(array));
    }
}

7、面向对象

7.1、类和对象

面向对象的概念

面向对象(Object Oriented)是一种编程模式,把业务相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式。

面向过程和面向对象的区别是:

  • 面向过程主要关注实现功能的步骤,关注实现细节。
  • 面向对象主要关注对象以及对象之间的关系,不关注实现细节。

类和对象

  • 类是对象的抽象,是模板
  • 对象是类的具体

面向对象编程

面向对象编程(Object Oriented Programming),就需要借助类和对象来实现。
OOP 编程的过程是:

  1. 定义类
  2. 使用类创建对象
  3. 调用对象的属性或方法
    定义类的语法是:
public class 类名{
	属性
	方法
}

构造方法

构造方法有什么作用?

  • 创建对象并且分配内存
  • 方便对对象的属性进行初始化

如何定义构造方法?

  • 名称和类名相同
  • 没有返回值类型
  • 可以有参数也可以没有
public 类名(){
}
public 类名(类型 参数..){
}

默认的构造方法:

  • 如果没有定义构造方法,编译器会自动为类添加一个无参的空的构造方法,类似: public 类名(){}
  • 如果我们手动添加了构造方法,编译器会删除掉这个默认的构造方法。
  • 一般情况下我们如果给类添加有参构造方法的同时,会手动添加一个无参的构造方法,方便无参的情况下创建对象。

this关键字

this代表当前的对象。

this关键字的作用是:

  1. 调用当前对象的属性,this.属性
  2. 调用当前对象的方法,this.方法名(…);
  3. 调用当前对象的构造方法,this(…)

构造方法里使用this的原因是参数名称和属性名称相同,为了区分它们,用this调用属性,没有this调用的就是参数

this.name = name;

对象的内存分配

JVM是虚拟的计算机,把内存分为5大区域管理:

  1. 程序计数器
    保存线程上下文的执行代码行数
  2. 本地方法区
    保存native方法的相关信息
  3. 方法区
    保存类信息、静态变量、常量等
  4. 虚拟机栈
    保存局部变量、对象的引用(内存地址)

  5. 保存真实的对象

方法区中保存着类,
一旦使用new,就会在堆中分配内存,保存对象,
栈区保存的是堆区对象的内存地址。

7.2、封装

封装的特性

什么是封装?
封装这个词语,包含两层含义:

  1. 包装
    将代码包装起来成为整体,方便调用和维护
  2. 封闭
    信息的隐藏,将实现的细节隐藏起来,提高安全性

封装的好处

  1. 安全性高
  2. 使用方便
  3. 维护性高

封装的实现

  1. 包装代码
    将代码包装到方法中,将属性和方法包装到类中,将类保存到包中…
  2. 信息隐藏
    隐藏某些不想被其他类调用的属性、方法和类

访问修饰符

访问修饰符是Java中的关键字,用于限制属性、方法、类的访问范围
访问修饰符有:

  1. public
  2. protected
  3. default
  4. private
访问权限子类其他类
publicYYYY
protectedYYYN
defaultYYNN
privateYNNN

属性的封装

Java类中一般将属性定义为私有的,然后提供公开的getter/setter方法对属性进行访问和修改

private double price;
//返回属性的值
public double getPrice(){
	return this.price;
}
//修改属性的值
public void setPrice(double price){
	this.price = price;
}

这么写的好处:

  • 在set方法中可以控制值的范围
if(price < 0){
	System.out.println("价格不能小于0");
	this.price = 0;
}else{
	this.price = price;
}
  • 可以控制属性: 读写、只读、只写

包的封装

什么是包?
类似于文件夹,把有相关功能的类保存到一起。
作用:

  • 方便进行查找
  • 避免命名冲突

创建包(package代码必须是类中的第一句):

package 包名;

导入包中的类(在一个包中的类,不需要导入):

import java.util.Scanner; 导入一个类
import java.util.*; 导入包中的所有类

7.3、继承

继承概述

可以由子类继承父类的成员(属性和方法),起到代码重用的作用
特点:

  • 程序中的类分为父类和子类
  • 子类可以继承父类,也可以说父类派生子类
  • 子类可以继承父类的属性和方法,是一种代码重用的机制

继承的语法

public class 子类 extends 父类{

} 

Java中的继承的特性

  • 传递性,父类的成员可以传递给子类,以及子类的子类
  • 单根性,子类只能有一个父类

super关键字

super代表父类对象
作用有:

  • 调用父类的属性
super.属性
  • 调用父类的方法
super.方法(..)
  • 调用父类的构造方法
super(参数);

super和this的区别

  • this代表当前类的对象,super代表父类的对象
  • this可以调用当前类的属性和方法(包括自身特有和父类的)
    super只能调用父类的属性和方法
  • this可以调用自身的构造方法,super可以调用父类的构造方法

super调用父类的构造方法:

给父类添加构造方法:
public Person() {
	System.out.println("这是Person无参的构造方法");
}
public Person(String name, int age) {
	this.name = name;
	this.age = age;
	System.out.println("这是Person带参的构造方法");
}

给子类添加构造方法:
public Student(){
	System.out.println("这是Student无参的构造方法");
}

public Student(String no,String name,int age) {
	//调用了父类的构造方法
	super(name,age);
	this.no = no;
	System.out.println("这是Student带参的构造方法");
}

调用子类:
Student stu = new Student();
Student stu1 = new Student("001","张三",20);

//运行结果
//这是Person无参的构造方法
//这是Student无参的构造方法
//这是Person带参的构造方法
//这是Student带参的构造方法

注意:

  • 子类如果不写super,系统会默认调用父类无参的构造方法
  • 调用父类有参构造方法时,子类必须使用super显式的调用父类的构造方法
  • super()必须出现在子类构造方法的第一行
  • 构造方法的调用,总是先调用父类的,再调用子类的

方法重写

什么是方法重写?
子类中的方法可以覆盖父类中的方法。

方法重写的特点:

  • 方法在子类和父类中
  • 方法名相同
  • 参数、返回值都相同
  • 子类方法的访问修饰符不能比父类更严格

Object类

Object类是Java中一切类的父类
Object类的常用方法:

  • equals 比较是否相等
  • hashCode 返回哈希代码
  • getClass 返回对象的类型信息
  • toString 返回对象的字符串信息

= =和equals的区别:
= =对于基本类型,比较的是值;对于引用类型,比较的是内存地址。
Object类的equals比较的也是对象的地址,因为源码中是用= =实现的。

public boolean equals(Object obj) {
    return (this == obj);
}

对于String类型来说,equals比较的是字符内容,因为String类重写了Object类的equals方法。

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}
int x = 10;
int y = 10;
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(x == y); // true
System.out.println(str1 == str2); // false
System.out.println(str1.equals(str2)); // true

final关键字

用于修饰类、变量、方法:

  • 被final修饰的类,不能被继承
  • 被final修饰的变量变成常量,不能修改值
  • 被final修饰的方法,不能重写

抽象方法和抽象类

在实际开发过程中,有时候我们需要把某些方法的具体实现,推迟到子类中实现。
抽象方法的意义在于:

  • 可以规范方法的定义(返回值类型、方法名、参数)
  • 具体实现由子类完成

抽象方法:

public abstract 返回值 方法名(类型 参数);

抽象类:

abstract class 类名{

}

注意:

  • 一旦类中定义了一个抽象方法,这个类必须定义成抽象类
  • 有抽象方法的类,必须是抽象类;抽象类不一定有抽象方法

抽象类的特点:

  • 抽象类不能实例化
  • 抽象类必须由子类继承并实现其中的抽象方法,除非子类也是抽象的

7.4、多态

多态的概念

多态(Polymorphism)意思就是事物具有多种状态,如水随着温度变化会在液态、固态、气态三种状态之间转换,人到了不同的国家会转换为中国人、美国人、印度人等。

作用:多态提高了程序的灵活性和扩展性。

多态的实现

多态性基于封装和继承机制,必须满足以下条件:

  • 子类继承了父类
  • 子类重写了父类的方法
/**
 * 人类
 */
abstract class Human {
	public abstract void eat();
}
/**
 * 中国人
 */
class Chinese extends Human{
	public void eat(){
		System.out.println("中国人拿筷子吃");
	}
}
/**
 * 美国人
 */
class American extends Human{
	public void eat(){
		System.out.println("美国人拿刀叉吃");
	}
}
/**
 * 印度人
 */
class Indian extends Human{
	public void eat(){
		System.out.println("印度人拿手吃");
	}
}

多态有几种实现的方式:

  1. 将子类的对象赋值给父类的引用
    对象调用父类的方法
public class HumanTest{
	public static void main(String[] args) {
		Human man1 = new Chinese();
		man1.eat();
		Human man2 = new American();
		man2.eat();
		Human man3 = new Indian();
		man3.eat();
	}
}
  1. 将方法的参数定义为父类类型,传入子类对象
public static void service(Human man){
	man.eat();
}

public static void main(String[] args) {
	service(new Chinese());
	service(new American());
	service(new Indian());
}
  1. 将方法的返回类型定义为父类类型,返回子类对象
public static Human getHuman(int type){
	Human man = null;
	switch(type){
	case 1:
		man = new Chinese();
		break;
	case 2:
		man = new American();
		break;
	case 3:
		man = new Indian();
		break;
	}
	return man;
}

public static void main(String[] args) {
	Human man1 = getHuman(1);
	Human man2 = getHuman(2);
	Human man3 = getHuman(3);
	man1.eat();
	man2.eat();
	man3.eat();
}

向上转型和向下转型

向上转型
子类对象转为父类类型

Human person = new Chinese();

向下转型
父类对象转为子类类型

如:子类类型 对象= (子类类型)父类对象;

向下转型的前提是:先向上转型

//向上转型
Human  person = new Chinese();
//向下转型
Chinese ch = (Chinese)(person);
ch.eat();

注意:向下转型存在类型转换错误的风险

Human  person = new Chinese();
//出现 ClassCastException 类型转换异常
Indian ch = (Indian)(person);

instanceof 运算符

instanceof 作用:判断一个对象是否是某个类型的

对象 instanceof 类型
返回boolean类型结果

7.5、static关键字和单例模式

static关键字

static的意思是静态,可以用来修饰类的属性和方法,一旦被static修饰的属性和方法,就会由类的所有对象共享,而不是属于某一个对象。

当某些属性和方法不想被对象调用时,就可以定义成静态的。

静态属性
语法:

static 类型 属性名;

静态属性的调用:

类名.属性名
也可以使用:对象名.属性
一般推荐使用类名调用静态成员

静态常量
开发过程中我们需要一些固定的数据,如:圆周率 3.1415926

public static final double PI = 3.1415926

优点:

  • 可读性高
  • 提高数据的安全性
  • 调用和维护方便

静态方法
定义:

public static 返回值类型 方法名(参数){
}

调用:

类名.方法名(参数)

注意:

  • 静态方法中可以直接调用当前类的其它静态属性和方法
  • 静态方法中不能直接调用当前类的非静态方法属性和方法
  • 非静态方法中可以直接调用当前类的静态和非静态的属性和方法
  • 静态方法中不能出现this和super关键字

Java中的各种工具类都大量使用静态方法,如:Arrays、Math等。

静态代码块
语法:

static{
	代码块
}

作用:
对静态的成员进行初始化

特点:

  • 静态代码块只执行一次
  • 在类加载到内存后执行,是类中所有代码最先执行
  • 在第一次使用类的使用调用

执行顺序:

  1. 静态代码块(只执行一次)
  2. 非静态代码块(每个对象执行一次)
  3. 构造方法(每个对象执行一次)

静态导入
jdk1.5的特性,导入某个类的静态方法后,可以不通过类名直接调用。

//静态导入
import static java.util.Arrays.sort;

public class Test3 {

	public static void main(String[] args) {
		int[] array = {3,5,7,8,2};
		//直接调用
		sort(array);
		for(int n : array){
			System.out.println(n);
		}
	}
}

单例模式

设计模式是前人针对不同的应用需求总结一套解决方案,常见的设计模式有23种,也称为GOF23。
单例模式属于GOF23中的创建性模式,作用是:保证一个类只能创建一个实例

单例模式的应用场景:

  • 某些业务场景,如:公司只有一个老板
  • 减少大型对象对系统资源的消耗,如:连接池、线程池

如何实现单例模式?
步骤:

  1. 将构造方法定义成private的
  2. 在单例类的内部定义一个该类的静态对象
  3. 定义一个静态方法用于返回静态对象

单例模式分为:饿汉式和懒汉式

区别是:

  1. 饿汉式,一开始就创建对象
    优点:代码简洁
    缺点:如果方法没有调用,就浪费了内存
  2. 懒汉式,开始不创建对象,当方法被调用后,再创建对象
    优点:内存的分配更高效
    缺点:有线程安全问题

7.6、接口和内部类

接口

定义接口的语法:

public interface 接口名{
	静态常量的定义;
	方法的定义;
}

定义接口要注意:

  • 方法是abstract的,不能实现
  • 定义的属性会自动转变为静态常量
  • 方法只能是public的,默认是public

实现接口:

public class 类名 implements 接口名{
	具体方法的实现
}

实现接口要注意:

  • 必须实现所有接口中的方法
  • 方法必须和接口中定义的完全一致
  • 方法必须是public的
  • 一个类可以实现多个接口
  • 一个类可以继承类同时实现接口
class 类名 extends 父类 implements 接口{
}
  • 接口可以继承接口,实现类必须实现所有的方法
interface A{
	void testA();
}
//接口之间的继承
interface B extends A{
	void testB();
}
class C implements B{
	public void testA() {
	}
	public void testB() {
	}
}

接口在开发中的意义:

  • 为类的实现制定一套规范
  • 把设计和实现分开

default关键字
Java1.8的新特性,被default定义的方法可以有默认的实现。

public interface Person {
	//给接口方法默认的实现
	default void eat(){
		System.out.println("在吃饭!!");
	}
	void walk();
}

实现类不强制要求实现带default的方法。

接口与抽象类的异同
相同点:

  • 都可能存在没有实现的方法
  • 都不能实例化
    不同点:
  • 抽象类是单一继承,类可以实现多个接口
  • 接口不能定义构造方法
  • 接口中的方法只能是public,抽象类可以有各种访问类型的方法。
  • 接口中只能定义静态常量,抽象类可以定义普通的成员变量。
  • 接口中的抽象方法不用加abstract,抽象类必须加。

内部类

内部类就是在类里面定义的类。
Java的内部类包含:

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类

匿名内部类
一个没有名字的内部类,创建类的同时创建了对象。
应用场合:接口或抽象类的实现类只需要使用一次,代码是一次性的。
语法:

new 接口/抽象类()
{
	实现方法
};

实现USB案例:

//Usb接口
interface Usb{
	void connect(); //连接
	void charge(); //充电
}
//匿名内部类实现接口
Usb usb = new Usb(){
	public void connect(){
		System.out.println("Test2测试连接");
	}
	public void charge(){
		System.out.println("Test2测试充电");
	}
};
usb .connect();
usb .charge();

和一般类的区别:

  • 没有名字
  • 只能使用一次
  • 没有构造方法
  • 不能定义静态成员

在?处填写什么可以在控制台输出30,20,10。

class Outer {
 	public int num = 10;
     class Inner {
         public int num = 20;
         public void show() {
             int num = 30;
             System.out.println(?);   	num
             System.out.println(?);   	this.num
             System.out.println(?); 	Outer.this.num
         }
     }
 }

 class InnerClassTest {
     public static void main(String[] args) {
         Outer.Inner oi = new Outer().new Inner();
         oi.show();
     }    
 }   

8、Java常用类

  • 字符串相关:String、 StringBuffer、 StringBuilder
  • 包装类:Integer等
  • 日期相关: Date、 Calendar、 SimpleDateFormat
  • 其他:Math、Random、Runtime、System

8.1、字符串相关

String类

创建方式1:赋值常量

String str = "hello";

使用双引号括起来的内容叫字符串常量值,字符串常量值分配在方法区的常量池中。
常量池的好处:

  • 节约内存,反复使用,不需要重新分配
  • 性能高,直接调用,省去创建对象的时间

创建方式2:使用new创建对象

String name = new String("zhangsan");

StringBuilder类

如果字符串变量需要频繁修改,就会创建大量字符串对象,大量消耗内存空间。

String和StringBuilder的区别:

  • String的字符串是不可修改,如果修改会创建新字符串,浪费内存。
  • StringBuilder的字符串是可以修改的,不会创建新字符串。

为了解决这个问题,可以使用StringBuilder。

创建方式:

创建空值的对象
StringBuilder strb = new StringBuilder();
创建有默认值的对象
StringBuilder strb = new StringBuilder("默认值");

StringBuffer类

StringBuffer的特点和StringBuilder相似,都是在自身的数组上进行的修改,常用方法也一样。
不同点:

  • StringBuffer的方法是线程安全的,StringBuilder是非线程安全的
  • StringBuilder的执行效率高于StringBuffer

8.2、包装类

Java中的8种基本数据类型不是引用类型,也不能创建对象,这就违背了Java是完全面向对象语言这一前提。Java推出8个包装类,把基本类型包装成对象。
包装类包装了8种基本数据类型,把基本数据类型看做对象进行处理。

基本类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

创建方式:

Integer num1 = 1000;Integer num2 = new Integer(1000);

装箱和拆箱

装箱与拆箱是基本数据类型和引用类型的相互转换。

  • 装箱:基本数据类型转换为引用类型
    如: Integer n = 200;
  • 拆箱:引用类型转换为基本数据类型
    如:Integer n = 200;
    int m = n; //拆箱

字符串与基本类型的转换

字符串转换为int类型

String s = "1234";
int num = Integer.parseInt(s);

其他类型

Float.parseFloat(字符串)   转换为Float
Double.parseDouble(字符串) 转换为Double
... 

int类型转换为字符串

String s = String.valueOf(num);

int num = 20;
String s = "" + num;

8.3、日期和时间处理

Date类

处理日期时间
创建方法1:

Date date = new Date(); 获得当前的时间

创建方法2:

Date date = new Date(long); 指定时间的1900-1-1到现在的毫秒数

常用方法

int getYear()			获得年
int getMonth()			获得月
int getDate()			获得天
int getHours()			获得小时
int getMinutes()		获得分钟
int getSeconds()		获得分钟
void setYear(int year) 	设置年
...

Calendar 类

日历类可以获得和修改日期的某个部分
创建Calendar对象

Calendar calendar = Calendar.getInstance();

常用方法

get(日期类型)	   		获得日期的某个部分
Calendar.YEAR
Calendar.MONTH	  		月份从0开始
....
set(日期类型,数值)		设置日期的某个部分
add(日期类型,数值)		实现日期某个部分的追溯

SimpleDateFormat类

对日期进行格式化
创建对象

SimpleDateFormat sdf = new SimpleDateFormat("日期格式字符串");
日期格式字符串,如:"yyyy-MM-dd hh:mm:ss"
yyyy	代表4位的年份
MM		代表2位的月份
dd		代表2位的日期
hh/HH	12小时制/24小时制
mm		代表分钟
ss		代表秒钟
a		代表AM/PM

将日期进行格式化

String format(Date对象);

将字符串转换为日期

Date parse(String对象);

8.4、其他类

Math类

Random类

获得随机数

Random random = new Random();
random.nextInt(100); //0 ~ 100间随机整数

Runtime类

System类

9、集合

9.1、集合框架体系

集合框架体系
接口特点:

  • Collection接口
    定义了集合的通用方法,如:添加、删除、集合个数
  • List接口
    可以排序、可以添加重复的数据
  • Set接口
    不能单独访问,数据不能重复
  • Map接口
    键值对,通过键访问

9.2、如何选择集合

在开发过程中,需要根据实际业务场景,结合集合的特点选择集合

  • 可以排序,可以添加重复数据,可以随机访问 ----- List
    - 对数据访问要求高 ----- ArrayList
    - 对插入和删除要求高 ----- LinkedList
  • 不能添加重复的数据,不需要随机访问 ------ Set
    - 没有顺序 ----- HashSet
    - 可以进行排序 ----- TreeSet
    - 保留添加顺序 ----- LinkedHashSet
  • 可以进行快速查找 ,以键值对保存------ Map
    - 键没有顺序 ----- HashMap
    - 键可以排序 ----- TreeMap
    - 键保留添加顺序 ----- LinkedHashMap

10、异常

10.1、异常体系结构

异常体系结构

10.2、常见异常

常见异常

10.3、try-catch异常处理

异常被处理后,程序可以正常运行
语法:

try{
	可能出现异常的代码
}catch(异常类型 ex){
	处理异常的代码
}

异常处理过程:

  • 如果try中的代码出现了异常,JVM会自动抛出异常,程序跳转到catch中执行异常处理,处理结束后程序正常执行。
  • 如果try代码中没有异常,try代码执行完,跳过catch执行后面的代码。

10.4、多重catch异常处理

语法:

try{
	可能出现异常的代码
}catch(异常类型1 ex){
	处理代码1}catch(异常类型2 ex){
	处理代码2}...

异常处理过程:

  • 一旦出现异常,把异常和每个catch块进行匹配,如果匹配成功就执行catch后结束
  • 如果不匹配再判断下一个catch的异常类型。
    注意:如果catch中出现其他异常的父类,父类异常必须放在最后

10.5、try-catch-finally异常处理

finally最终的,在finally中的代码无论如何都会执行
程序有部分代码,是必须执行,如:数据库连接关闭、文件流关闭、网络连接的关闭。

try{
	可能出现异常的代码
}catch(异常类型 ex){
	异常处理
}finally{
	如论如何都执行的代码
}

异常处理过程:

  • 如果try出现异常,跳转到catch执行处理,最后执行finally代码;
  • 如果try没有异常,try执行完,最后执行finally。

10.6、throws 和 throw关键字

throws关键字
用于方法声明异常,一旦方法声明异常,方法中可以不处理异常,由方法的调用者处理。
一般用于非运行时异常。
语法:

public 返回值类型 方法名(参数列表) throws 异常类型1, 异常类型2...{

}

throw关键字
用于手动抛出异常,给调用者进行提示
语法:

if(条件){
	throw new 异常类型("异常描述信息");
}

10.7、自定义异常

实现步骤:

  • 定义类继承Exception或其子类
  • 满足某些条件时,在方法中用throw抛出异常
  • 在声明方法时,用throws声明异常
  • 调用方法时,使用try-catch处理异常

11、IO流

11.1、IO流分类

IO流分类

11.2、文件读写

文件读取

文件读取的过程

  1. 创建文件输入流
  2. 创建byte数组
  3. 循环调用read方法读取数据,存入byte数组
  4. 操作byte数组
  5. 读取完毕关闭文件流

文件读取

文件写入

文件写入步骤:

  1. 创建文件输出流
  2. 将字符串转换为byte数组
  3. 调用write写入文件
  4. 关闭文件流

文件复制

文件的复制是在读取文件的同时,将数据写入到另一个文件中
思路:

  1. 创建输入流和输出流
  2. 通过输入流读取数据到byte数组中
  3. 同时将byte数组中的数据写入输出流
  4. 循环1、2、3

文件复制

11.3、缓冲

11.4、字符流

11.5、打印流

11.6、数据流

12、网络编程

12.1、IP

IP地址指的是互联网地址(Internet Protocol Address ,是联网设备与互联网之间的唯一标识,在同一个网段中,IP地址是唯一的
IP地址是数字型的,是一个32位的二进制,通常将其分成4个8位的二进制数,每8位之间用圆点隔开,每个8位整数可以转换为一个0~255的十进制整数,例如:202.9.128.88

12.2、端口

IP地址可以唯一的确定网络上的一个通信实体,但一个通信实体可以有多个通信程序同时提供网络服务,此时还需要使用端口

数据的发送和接收都需要通过端口出入计算机,端口号用于唯一标识通信实体上进行网络通讯的程序,同一台机器上不能两个程序占用同一个端口

端口号的取值范围:0 ~ 65535

12.3、Socket编程

12.4、TCP

三次握手和四次挥手

12.5、UDP

TCP和UDP同属于传输层协议,对比TCP和UDP:
TCP/UDP

13、JVM

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值