1. Java三大版本
- JavaSE:标准版,主要应用在桌面程序、控制台开发...
- JavaME:嵌入式开发,主要应用在手机、小家电...,但是现在应用的不多
- JavaEE:企业级开发,主要应用在Web端、服务器开发...
2. JDK、JRE、JVM
- JDK:Java Development Kit,Java开发者工具
- 包含JRE和JVM
- JRE:Java Runtime Environment,Java运行时环境
- 包含JVM,如果只是为了运行Java程序,只需要安装JRE即可
- JVM:JAVA Virtual Machine,Java虚拟机
- 运行Java字节码的虚拟机,JVM针对不同的系统有特定的实现(Windows、Linux、MacOS),目的是使用相同的字节码在不同的操作系统中给出相同的结果
- 运行Java字节码的虚拟机,JVM针对不同的系统有特定的实现(Windows、Linux、MacOS),目的是使用相同的字节码在不同的操作系统中给出相同的结果
3. Java开发环境搭建
- JDK下载与安装
- 下载JDK 8
- 安装JDK
- 配置环境变量
- 添加系统环境变量JAVA_HOME:C:\Program Files\Java\jdk1.8.0_202
- 添加系统环境变量Path:%JAVA_HOME%\bin、%JAVA_HOME%\jre\bin
- JDK目录介绍
- bin:Java可执行程序
- include:C&C++的头文件
- jre:Java运行时环境
- lib:libary,java的类库文件
- src:资源文件,源代码
4. Java程序运行机制
- 编译型:先编译再执行
- 整本书翻译完成后再阅读,如果书内容发生变化需要重新翻译
- 将代码编译成计算机可识别的
- 执行速度快
- 解释型:一遍执行一遍编译
- 翻译官一遍翻译一遍阅读,如果书内容发生变化即使翻译
- 一遍运行一遍编译成计算机可识别的
- 执行速度没有编译型快
- Java是编译型+解释型的语言
- 先通过编译器编译成class文件,再通过解释器解释class文件变成计算机可识别的语言
- 需要格外注意的是 .class->机器码这一步。在这一步 JVM 类加载器首先加载字节码文件,然后通过解释器逐行解释执行,这种方式的执行速度会相对比较慢。而且,有些方法和代码块是经常需要被调用的(也就是所谓的热点代码),所以后面引进了JIT(just-in-time compilation)编译器,而 JIT 属于运行时编译。当 JIT 编译器完成第一次编译后,其会将字节码对应的机器码保存下来,下次可以直接使用。而我们知道,机器码的运行效率肯定是高于 Java 解释器的。这也解释了我们为什么经常会说 Java 是编译与解释共存的语言
- 先通过编译器编译成class文件,再通过解释器解释class文件变成计算机可识别的语言
著作权归Guide哥所有。
链接: https://javaguide.cn/java/basis/java基础知识总结/#什么是字节码-采用字节码的好处是什么
- IntelliJ IDEA
- UserName:lv.feng@outlook.com
- Password:7u5-8dtabuZZBZq
5. Java基础语法
-
注释
- 单行注释
//程序入口 public static void main(String[] args){ }
- 多行注释
/* * 程序入口 * */ public static void main(String[] args){ }
- 文档注释
/** * @author lvfneg * @version jdk1.8 */ public static void main(String[] args){ }
- 单行注释
-
标识符
- 关键字:不能使用系统关键字
- 所有的标识符都应该以字母、美元符、下划线开始
- 首字母之后可以是字母、美元符、下划线、数字或任何字符组合
- 不能使用关键字作为变量名或方法名
- 标识符大小写敏感
- 可以使用中文命名,但不建议,也不建议使用拼音
-
数据类型
- 强类型语言:要求变量的使用严格符合规定,所有变量都必须先定义才能使用
- 弱类型语言
- Java的数据类型分为两大类
- 基本类型(primitive type)
- 数值类型
- 整数类型
- byte:占1个字节,范围-128到127
- short:占2个字节,范围-3278到32767
- int:占4个字节,范围-21474838到214748367
- long:占8个字节,范围-9223372036854775808到9223372036854775807
//long类型要在数字后加L long number = 127L; 整数扩展 1、二进制:0B开头 2、八进制:0开头 3、十进制:阿拉伯数字 4、十六进制:0x开头
- 浮点类型
- float:占4个字节
- double:占8个字节
//float类型要在数字后面加F float number = 50.1F; 浮点数扩展 1、float:有限、离散,有舍入误差,实际结果为大约或者接近但不等于
- 字符类型:char占2个字节
- 所有的字符本质都是数字,通过Unicode进行编码,Unicode表示数字和字符的关联关系
- 转义字符
- \t:空格
- \n:换行
- 整数类型
- boolean类型:占1个字节,只有true和false
bollean isTrue = true;
- 数值类型
- 引用类型(reference type)
- 类
- 接口
- 数组
- 什么是字节
- 位(bit):计算机内部数据存储的最小单位,11001100是一个八位二进制
- 字节(byte):计算机中数据处理的基本单位,习惯上用大写B来表示
1B(byte,字节):8bit(位)
- 字符:指计算机中使用的字母、数字、字和符号
1bit表示1位 1Byte表示一个字节1B=8b 1024B=1KB 1024KB=1M 1024M=1G
- 基本类型(primitive type)
-
类型转换
- 由于Java是强类型语言,所以要进行有些运算的时候,需要用到类型转换
低------------------------------------>高 1、根据存储长度从低到高排序 2、long比float和double都长,但是排在其后,因为小数优于整数 byte,short,char->int->long->float->double
- 运算中,不同类型的数据先转换为同一类型,然后进行计算
- 强制类型转换
- 由高转到低需要强制转换,由高到底强制转换时容易出现内存溢出的问题(高等级的存储长度超过低等级就会出现内存溢出)
- 自动类型转换
- 由低到高自动类型转换
注意:
1、不能对boolean值进行转换
2、不能把对象类型转换为不相干的类型
3、把高等级转换为低等级时,进行强制转换
4、转换的时候可能存在内存溢出或者精度问题
5、操作比较大的数的时候,注意溢出问题 int money=10_0000_0000 - 由于Java是强类型语言,所以要进行有些运算的时候,需要用到类型转换
-
Java编写规范
- 类成员变量:首字母小写和驼峰原则,除了第一个单词以外,后面的单词首字母大写
- 局部变量:首字母小写和驼峰原则
- 常量:全部大写,可以添加下划线
- 类名:首字母大写和驼峰原则
- 方法名:首字母小写和驼峰原则
-
运算符
- 算数运算符:+、-、*、/、%、++、--
- 一元运算符
- ++、--
int a = 10; //++在后,先赋值再运算 int b = a++; //++再前,先运算再赋值 int c = ++a;
- 一元运算符
- 赋值运算符:=
- 关系运算符:>、<、>=、<=、==、!=
- 逻辑运算符:&&、||、!
- 位运算符:&、|、^、~、>>、<<、>>>
- 效率极高,直接使用二进制,不需要进行转换成二进制
A = 0011 1100 B = 0000 1101 //与运算符,A和B进行比较,如果对应位两个都为1结果为1,反之为0 A&B:0000 1100 //或运算符,A和B进行比较,如果对应位两个都为0结果为0,反之为1 A|B:0011 1101 //异或运算符,A和B进行比较,如果对应位相同为结果为0,反之为1 A^B:0011 0001 //取反运算符 ~B:1111 0010 //左移、右移 0000 0000:0 0000 0001:1 0000 0010:2 0000 0011:3 0000 0100:4 0000 0101:5 0000 0110:6 0000 0111:7 0000 1000:8 <<:当前数值*2或者向前进一位 >>: 当前数值/2或者向后退一位
- 条件运算符:?:
- 扩展赋值运算符:+=、-=、*=、/=
- 算数运算符:+、-、*、/、%、++、--
-
包机制
- 为了更好的组织类,Java提供了包机制,用于区别类名和命名空间
- 包语句的语法格式
package pkg1[. pkg2[. pkg3...]]
- 一般利用公司域名倒置作为包名:com.iservice.www,com.iservice.dbhelper
- 为了能够使用某一个包的成员,需要在Java程序中明确导入该包,使用"import"语句
//*导入包中的所有类 import pkg1[. pkg2...].(classname|*)
-
JavaDoc
- javadoc命令是用来生成API文档的
- 参数信息
- @author:作者名
- @version:版本号
- @since:指明需要最早使用的jdk版本
- @param:参数名
- @return:返回值
- @throws:异常抛出情况
//生成doc语法,命令行模式 javadoc -encoding UTF-8 -charset UTF-8 Hello.java
6. Java流程控制
-
用户交互Scanner
- 通过Scanner工具类,可以获取用户的输入
//基本语法 public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("使用next方式接收:"); //判断用户是否输入字符串 if(scanner.hasNext()){ String userInput = scanner.next(); System.out.println("输入的内容:" + userInput); } scanner.close(); }
- 通过Scanner类的next()与nextLine()方法获取输入的字符串,再读取前我们一般需要使用hasNext()与hasNextLine()判断是否还有输入数据
- next()
- 一定要读取到有效字符后才可以结束输入
- 对输入有效字符之前遇到的空白,next()方法会自动将其去掉
- 只有输入有效字符后才能将后面输入的空白作为分隔符或者结束符
- next()不能得到带有空格的字符串
- nextLine()
- 以Enter为结束符,也就是说nextLine()方法返回的是输入回车之前的所有字符
- 可以获得空格
- next()
- 通过Scanner工具类,可以获取用户的输入
-
顺序结构
- JAVA的基本结构就是顺序结构,除非特别说明,否则就按照顺序一句一句执行
- 顺序结构是最简单的算法结构
- 语句与语句之间,框与框之间是按从上到下顺序执行的,它是若干的依次执行的处理步骤组成的,它是任何一个算法都离不开的一种基本算法结构
-
选择结构
- if单选择结构
- if双选择结构
- if多选择结构
- 嵌套的if结构
- switch多选择结构
- switch语句中的变量类型可以是
- byte、short、int或者char
- 从Java SE7开始,switch支持字符串String类型
- 同时case标签必须为字符串常量或字面量
- switch语句中的变量类型可以是
-
循环结构
- while
- do...while
- for
//死循环 for(;;){ }
- 在Java5中引入了一种主要用于数组的增强型for循环
- Java增强for循环语法格式如下
int[] numbers = {1,2,3,4,5,6}; for(int x:numbers){ System.out.println(x); }
- 声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配,其作用域限定在循环语句块,其值与此时数据元素的值相等
- 表达式:表达式是要访问的数组名,或者返回值为数组的方法
- Java增强for循环语法格式如下
-
break & continue
- break:在任何循环语句的主体部分,均可用break控制循环的流程,break用于强行退出循环,不执行循环中剩余的语句
- continue:用在循环语句体中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定
- 关于goto关键字
- goto关键字很在就在程序设计语言中出现,尽管goto仍是Java的一个保留字,当并未在语言中得到正式使用,Java没有goto,然而在break和continue这两个关键字身上仍然能看出一些goto的影子,也就是带标签的break和continue
- 标签:指后面跟着一个冒号的标识符,例如:lable:
- 对Java来说唯一用到标签的地方是在循环语句之前,而在循环之前设置标签的唯一理由是,我们希望在其中嵌套另一个循环,由于break和continue关键字通常只中断当前循环,但若随同标签使用,他们就会中断到存在标签的地方
int count = 0; outer:for(int i=101;i<150;i++){ for(int j=2;j<i/2;j++){ if(i%j==0){ continue outer; } } }
7. 方法详解
-
何谓方法
- Java方法是语句的集合,它们在一起执行一个功能
- 方法是解决一类问题的步骤的有序组合
- 方法包含在类或对象中
- 方法在程序中被创建,在其他地方被引用
- 设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合,我们设计方法的时候,最好保持方法的原子性(一个方法只完成一个功能,这样有利于后期的扩展)
- Java方法是语句的集合,它们在一起执行一个功能
-
方法重载
- 重载就是在一个类中,有相同的函数名称,但形参不同的函数
- 重载的规则
- 方法名称必须相同
- 参数列表必须不同(个数不同、类型不同、参数排列顺序不同)
- 方法的返回类型可以相同或不同
- 仅仅返回类型不同不足以成为方法的重载
- 实现理论
- 方法名称相同时,编译器会根据调用方法的参数个数、类型等去逐个匹配,以选择对应的方法,如果匹配失败编译器会报错
-
命令行传参
- 运行一个程序时传递给他消息,这要靠传递命令行参数给main()函数实现
-
可变传参
- JDK5开始,Java支持传递同类型的可变参数给一个方法
- 在方法声明中,在指定参数类型后加一个省略号(...)
- 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数,任何普通的参数必须在它之前声明
-
方法的调用
- 静态方法
- 非静态方法
- 形参和实参
- 值传递和引用传递
- this关键字
8. 数组
-
数组概述
- 一组相同类型数据的有序集合
- 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合
- 其中,每一个数据称作为一个数组元素,每个数组元素可以通过一个下标来访问它们
-
数组声明&创建
- 数组的默认初始化:数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化
//声明 int[] numbers; int numbers[]; //创建 int[] numbers = new int[10]; int[] numbers = new int[]{1,2,3,4,5}; //获取数组长度 int count = numbers.length;
- 数组的四个基本特别
- 长度确定,一旦创建大小不可被改变
- 其元素必须是相同的类型
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型
- 数组变量属于引用类型,数组可以看成是一个对象,数组中的每个元素相当于该对象的成员变量
- 数组本身就是对象,Java的对象是在堆中,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的
-
内存分析
- Java内存分析
- 堆
- 存放new的对象和数组
- 可以被所有的线程共享,不会存放别的对象引用
- 栈
- 存放基本变量类型(包含这个基本类型的具体数值)
- 引用对象的变量(会存放这个引用在堆里面的具体地址)
- 方法区
- 可以被所有的线程共享
- 包含了所有的class和static变量
- 堆
- Java内存分析
-
数组使用
- for循环
- For-Each
int[] numbers = {1,2,3,4,5}; for(int i : numbers){ System.out.println(i); }
- 数组作为方法入参
- 数组作为返回值
-
多维数组
- 多维数组可以堪称数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组
- 二维数组
//数组a可以看成一个两行五列的数组 int a[][] = new int[2][5]; //数组b可以看成一个两行三列的数组 int b[][] = {{1,2},{3,4},{5,6}};
-
Arrays类
- 数组帮助类
-
稀疏数组
- 定义
- 当一个数组中的大部分元素为0或者为同一值的数组时,可以使用稀疏数组来保存该数组
- 稀疏数组的处理方式
- 记录数组一个共几行几列,有多少个不同值
- 把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模
- 如下图,左边是原始数组,右边是稀疏数组
- 定义
9. 面向对象编程-OOP
-
初始面向对象
- 类是对事务的一中抽象,对象是一个具体的实例
-
面向对象三大特性
- 封装
- 程序设计要求高内聚、低耦合,高内聚就是类的内部数据操作细节自己完成,不允许外部干涉,低耦合就是仅暴露少量的方法给外部使用
- 优点
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 提高系统的可维护性
- 继承
- 集成的本质是对某一批类的抽象,从而实现对现实世界更好的建模
- extends的意思是”扩展“,子类是父类的扩展
- JAVA中只有单继承,没有多继承
- 继承是类和类之间的一种关系,除此之外,类和类之间的关系还有依赖、组合、聚合等
- 继承关系的两个类,一个为子类(派生类),一个为父类(基类),子类继承父类,使用关键字extends来表示
- 子类和父类之间,从意义上讲应该具有"is a"的关系
- object:所有类的父类
- 被final修饰的类不能被继承
/* Ctrl+H 可以查看类的继承关系 Alt+Insert 快速创建构造、属性方法 Ctrl+Alt+点击鼠标 跳转至实现 */ public class Person{ public void say(){ System.out.println("Hello World") } } public class Chinese extends Person{ } public static void main(String[] args){ new Chinese().save(); }
- super/this
- 调用本类&父类的构造器,必须放在第一行
public class Person(){ protected String name="parent"; } public class Chinese extends Person{ private String name="lvfeng"; public void test(string name){ //方法的参数 System.out.println(name) //当前类的字段 System.out.println(this.name) //父类的字段 System.out.println(super.name) } }
- 方法重写
- 只能重写非静态的public方法
public class Person(){ public void say(){ System.out.println("Hello World") } } public class Chinese extends Person{ @override public void say(){ System.out.println("Hello World") } }
- 多态
- instanceof
- 引用类型转换
if(chinese instanceof person){ return "父子关系"; }
- 封装
-
代码块
{ /* 匿名代码块:在静态代码块之后构造函数之前执行 */ } static { /* 静态代码块:构造函数之前执行且只执行一次 */ } //静态导入包 import static java.lang.Math.random; public static void main(String[] args){ System.out.println(random()); }
-
抽象类
- abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法该方法为抽象方法,如果修饰类该类为抽象类
- 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类
- 抽象类不能使用new关键字来创建它,它是用来让子类继承的
- 抽象方法只有方法的声明,没有方法的实现,它使用子类来实现的
- 子类继承抽象类,必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
public abstract class Action{ public abstract void go(); } public class Child extends Action{ @override public void go(){ } } public abstract class Child2 extends Action{ public abstract void go(); public void run(){ System.out.println("Hello World"); } } public static void main(String[] agrs){ Action action = new Child(); action.go(); }
-
接口
- 接口就是规范,定义的是一组规则或者约束
- 接口的本质就是契约,就像法律一样,制定好了大家一起遵守
- OO的精髓,是对对象的抽象,最能体现这一点的就是接口
- 接口中所有的定义其实都是抽象的public abstract
- 实现了接口的类,必须实现接口中的所有方法
public interface IAction{ //静态常量:public static final int AGE=99; void go(); } public interface IAction1{ void run(); } public class Action implements IAction,IAction1 { @override public void go(){ System.out.println("Hello World"); } @override public void run(){ System.out.println("Hello World"); } }
10. 异常
-
异常体系结构
- 检查性异常:用户错误或问题引起的异常,程序无法预见的,例如打开一个不存在的文件
- 运行时异常:运行时异常可能被程序员避免的异常,与检查性异常相反,运行时异常可以在编译时被忽略
- 错误:错误不是异常,是脱离程序控制的问题,错误在代码中通常被忽略,例如当栈溢出时一个错误就发生了,它们在编译也检查不到
- Java把异常当作对象来处理,并定义了一个基类java.lang.Throwable作为所有异常的基类
- 在Java中已经定义了很多异常类,这些异常类分为两大类,错误Error和异常Exception
- Error
- Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关
- Java虚拟机运行错误(Virtual MachineError),当JVM不在有继续执行操作所需的内存资源时将出现OutOfmemoryError,这些异常发生时,Java虚拟机一般会选择线程终止
- 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError),这些错误时不可查的,因为他们在应用程序的控制和处理能力之外,而且绝大多数时程序运行时不允许出现的状况
- Exception
- 在Exception分支中有一个重要的子类RuntimeException(运行时异常)
- 这些异常一般是由程序逻辑错误引起的
- Error和Exception
- Error通常时灾难性的致命错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机一般会选择终止线程
- Exception通常情况下是可以被程序处理的,并在程序中应该尽可能的去处理这些异常
- Error
-
Java异常处理机制
- 抛出异常
- 抓取异常
-
处理异常
- 异常处理的五个关键字
- try catch finally throw throws
- throw:主动抛出异常
public void scal(){ int a = 10 int b = 0; if(b==0){ throw new ArithmeticException(); } }
- throws:向上跑异常,在上层处理异常
public void scal() throws ArithmeticException{ int a = 10; int b = 0; int c = a / b; }
- 捕获多个异常,编写catch时需要从小到达编写
- Ctrl+Alt+T 快速生成异常捕获块
-
自定义异常
- Java内置的异常类可以描述在编程时出现的大部分异常情况,除此之外,用户还可以自定义异常,用户自定义异常,只需要继承Exception类即可
- 在程序中使用自定义异常,可以分为以下步骤
- 创建自定义异常类
- 在方法中通过throw关键字抛出异常对象
- 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理,否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作
- 在出现异常方法的调用者中捕获并处理异常
public class MyException extends Exception{ private int _numbers; public MyException(int numbers){ _numbers = numbers; } @override public String toString(){ return "MyException{"+_numbers+"}"; } }
11. Java常用类
-
内部类
- 定义
- 在一个类的内部再定义一个完整的类
- 一个Java类中可以有多个同等级的class类,但只能有一个public class
- 特点
- 编译之后可生成独立的字节码文件
- 内部类可直接访问外部类的私有成员
- 可为外部类提供必要的内部功能组件
- 成员内部类
- 定义:再类的内部定义,与实例变量、方法同级别
- 外部类的一个实列部分
- 当外部类和内部类属性出现重名时,优先使用内部类的属性
- 成员内部类不能定义静态成员
- 成员内部类可以包含静态常量 final
public class Outer{ private String name; private int age; class Inner{ private String name; private String address; private String phone; public void show(){ //打印内部类的name,如果内部类没有这个成员直接访问的外部类 System.out.println(name); //当出现重名时,使用如下方式调用外部类的属性 System.out.println(Outer.this.name); } } } public static void main(String[] args){ Outer outer = new Outer(); Inner inner = outer.new Inner(); Inner inner = new Outer().new Inner(); inner.show(); }
- 静态内部类
- 定义:
- 不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员,相当于一个外部类,他的级别和外部类相同
- 静态内部类不能直接使用外部类的属性,只能通过New的方式进行获取或者将外部类的属性设置成静态的,因为静态内部类的创建比外部类的非静态属性要早,所以静态内部类拿不到
public class Outer{ private String name; private int age; static class Inner{ private String address; private String phone; private static int count; public void show(){ Outer outer = new Outer(); System.out.println(outer.name); //访问静态内部类非静态成员 System.out.println(phone); //访问静态内部类静态成员 System.out.println(Inner.count); } } } public static void main(String[] args){ Outer.Inner inner = new Outer.Inner(); inner.show(); }
- 定义:
- 局部内部类
- 定义:定义在外部类的方法当中,作用范围和创建对象的范围仅限于当前方法
- 局部内部类不能使用访问修饰符
- 局部内部类不能使用静态属性,但是可以使用静态常量 final static
- 局部内部类访问外部类方法中的局部变量时,因为无法保证变量的生命周期与自身相同,变量必须修饰为final,但是在jdk1.8后不需要添加final修饰符,因为jdk1.8默认添加了
public class Outer{ private String name; private int age; public void show(){ String address; //定义局部内部类 class Inner{ private String phone; private String email; public void show2(){ //访问外部类属性 System.out.println(name); //访问内部类属性 System.out.println(phone); //访问外部方法的属性,jdk1.7要求变量必须是常量,jdk1.8自动添加final System.out.println(address); } } Inner inner = new Inner(); inner.show(); } } public static void main(String[] args){ new Outer().show(); }
- 匿名内部类
- 定义:没有类名的局部内部类(一切特征都与局部内部类相同)
- 必须继承一个父类或者实现一个接口
- 定义类、实现类、创建对象的语法合并,只能创建一个类的对象
- 优点:减少代码量
- 缺点:可读性差
public interface IOuter{ void service(); } public static void main(String[] args){ //局部内部类 class Inner implements IOuter{ @override public void service(){ System.out.println("Hello World"); } } IOuter outer = new Inner(); outer.service(); //匿名内部类 IOuter outer = new IOuter(){ @override public void service(){ System.out.println("Hello World"); } } outer.service(); }
- 定义
-
Object
- 定义
- 超类、基类,所有类的直接或间接父类,位于继承树的最顶层
- 任何类,如没有书写extends显示继承某个类,都默认直接继承object,否则为间接继承
- Object类中所定义的方法,是所有对象都具备的方法
- Object类型可以存储任何对象
- 作为参数,可接收任何对象
- 作为返回值,可返回任何对象
- 常用方法
- getClass
- 返回:Class
- 定义:返回引用中存储的实际对象类型
- 应用:通常用于判断两个引用中实际存储的对象是否一致
public class Student{ public String name; public int age; } public static void main(String[] args){ Student stu1 = new Student(); Student stu2 = new Student(); //判断stu1和stu2是否同一类型 Class c1 = stu1.getClass(); Class c2 = stu2.getClass(); if(c1 == c2){ return true; }else{ return false; } }
- hashCode
- 返回:int
- 定义
- 返回该对象的哈希码值
- 哈希值根据对象的地址或字符串或数字使用hash算法计算出来的int类型的数值
- 一般情况下相同对象返回相同的哈希码
- 应用:判断对象的内存地址是否相同
public class Student{ public String name; public int age; } public static void main(String[] args){ Student stu1 = new Student(); Student stu2 = new Student(); int stu1 = stu1.hashCode(); int stu2 = stu2.hashCode(); if(stu1 == stu2){ return true; }else{ return false; } }
- toString
- 返回:String
- 定义
- 返回对象的字符串表示(表现形式)
- 可以根据程序需求覆盖方法,如:展示对象各个属性值
public class Student{ private String name; //重写Object的toString() @override public String toString(){ return "Hello World"; } } public static void main(String[] args){ //返回对象的全名称+@+hashCode(16进制) String stu1 = stu1.toString(); String stu2 = stu2.toString(); }
- equals
- 返回:boolean
- 定义
- 比较两个对象地址是否相同
- 可进行重写,比较两个对象的内容是否相同
- equals和==的区别
- 基本数据类型:==比较值
- 引用数据类型:==比较的是对象的内存地址
- 因为Java只有值传递,对于==来说,不管是比较基本数据类型还是引用数据类型,其本质比较的都是值,只是引用类型变量存的值是对象的地址
- equals不能用于判断基本数据类型的变量,只能判断两个对象是否相等
public class Student{ private String name; @override public boolean equals(Object obj){ if(this == obj){ return true; } if(obj == null){ return false; } //判断对象的类型是否相同 <!-- if(this.getClass() == obj.getClass()){ return true; } --> if(obj instanceof Student){ Student stu = (Student)obj; if(this.name == stu.name){ return true; } } return false; } } public static void main(String[] args){ Student stu1 = new Student(); Student stu2 = new Student(); System.out.println(stu1.equals(stu2)); }
- finalize
- 当对象判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象,进入回收队列
- 垃圾对象:没有有效引用指向此对象时
- 垃圾回收:由GC销毁垃圾对象,释放数据存储空间
- 自动回收机制:JVM内存耗尽,一次性回收所有对象
- 手动回收机制:使用System.gc()通知JVM执行垃圾回收
public class Hello{ @override protected void finalize() throws Throwable{ System.out.println("对象堆GC回收了"); } } public static void main(String[] args){ Hello hello = new Hello(); //垃圾回收,执行此语句没有执行对象的finalize System.gc(); new Hello(); //垃圾回收,执行此语句执行了对象的finalize System.gc(); }
- getClass
- 定义
-
包装类
- 定义
- 基本数据类型所对应的引用数据类型
- 基本数据类型只能操作运算符,没有Object对应的方法,包装类就是基本数据类型所对应的引用数据类型,可以让基本数据类型使用Object对应的方法
- 完整的定义就是把基本数据类型包装成一个对象,使其变成一个引用类型,存放数据时也会从栈存放到堆中
- Object可统一所有数据,包装类的默认值是null
- 基本数据类型对应的引用类型
- byte:Byte
- short:Short
- int:Integer
- long:Long
- float:Float
- double:Double
- boolean:Boolean
- char:Char
- 定义
-
类型转换与装箱、拆箱
- 基本数据类型:存放在栈中
- 引用数据类型:存放在堆中
- 装箱:基本数据类型转换成引用数据类型,数据由栈存放在堆中
- 拆箱:引用数据类型转换成基本数据类型,数据由堆存放在栈中
/* JDK1.5之前 */ //装箱 int num = 18; Integer i1 = new Integer(num); Integer i2 = Integer.valueOf(num); //拆箱 num = i1.intValue(); /* JDK1.5之后,提供自动装箱和拆箱 */ //装箱 Integer i1 = num; //拆箱 num = i1;
-
整数缓冲区
- Java预算创建了256个常用的整数包装类型对象
- 在实际应用中,对已创建的对象进行服用
- 整数缓冲区范围-128——127
Integer i1 = new Integer(100); Integer i2 = new Integer(100); //当前结果返回false,因为Integer是引用类型,i1和i2的内存引用不同 System.out.println(i1 == i2); Integer i1 = 100; // 等同于 Integer i1 = Integer.valueOf(100); Integer i2 = 100; //当前结果返回true,因为上面的代码执行了自动装箱(valueOf)的操作,valueOf会从缓存中读取-127到128的数值,因为之前已经实例化,所以i1和i2的内存指向相同 System.out.println(i1 == i2); Integer i1 = 200; Integer i2 = 200; //当前结果返回false,即使走的也是valueOf方法,但200已经超过了整数缓冲区,所以会执行new Integer()重新创建一个新的对象 System.out.println(i1 == i2);
-
String类
- 字符串是常量,创建之后不可改变
- 字符串字面值存储在字符串池中,可以共享,字符串在方法区中
- Java内存存放区域类型
- 堆:存放引用类型
- 栈:存放基本类型
- 方法区:类、方法、静态变量+常量、字符串池
/* 产生一个对象,字符串池中存储 创建流程:先在栈开辟空间,然后判断字符串池中是否有Hello,如果有返回内存地址,反之则创建后返回地址 */ String str = "Hello"; /* 产生两个对象,堆、池各存储一个 创建流程:先在栈中开辟空间,然后判断字符串池中是否有Hello,如果有不进行任何操作,反之则开辟空间,最后在堆中开辟空间创建空对象,但是堆中的内存地址是字符串中的地址,然后将堆中的地址返回回去 */ String str = new String("Hello");
- Java内存存放区域类型
- 可变字符串
- StringBuffer:可变长字符串,JDK1.0提供,运行效率慢,线程安全
- StringBuilder:可变长字符串,JDK5.0提供,运行效率快,线程不安全
- 与String的区别
- 效率比String高
- 比String节省内存
StringBuffer sb = new StringBuffer(); sb.append("追加字符串"); System.out.println(sb.toString()); StringBuilder sb = new StringBuilder(); sb.append("追加字符串"); System.out.println(sb.toString()); //验证StringBuilder效率高于StringBuffer long start = System.CurrentTimeMillis(); String string=""; for(int i=0;i<99999;i++){ string+=i; } long end = System.CurrentTimeMillis(); System.out.println("用时:"+(end-start)); long start = System.CurrentTimeMillis(); StringBuffer string = new StringBuffer(); for(int i=0;i<99999;i++){ string.append(i); } long end = System.CurrentTimeMillis(); System.out.println("用时:"+(end-start)); long start = System.CurrentTimeMillis(); StringBuilder string = new StringBuilder(); for(int i=0;i<99999;i++){ string.append(i); } long end = System.CurrentTimeMillis(); System.out.println("用时:"+(end-start));
-
BigDecimal类
- double和float:近似值存储,在进行运算时会有偏差
- 在要求精度准确的情况下需要借助BigDecimal
//double和float在内存中存放的是一个近似值,所以计算出来的结果会有偏差 double d1 = 1.0; double d2 = 0.9; //d3并不等于0.1,而是0.999999998 double d3 = d1 - d2; BigDecimal n1 = new BigDecimal("1.0"); BigDecimal n2 = new BigDecimal("0.9"); //执行减法 BigDecimal n3 = n1.subtract(n2); /* 加法:add 乘法:multiply 除法:devide */
-
Date
- Date表示特定的瞬间,精确到毫秒。Date类中的大部分方法都已经被Calendar类中的方法所取代
-
Calendar
- 提供了获取和设置各种日历字段的方法
- 构造方法:protected Calendar():由于修饰符是protected,所以无法直接创建该对象
//创建对象 Calendar calendar = Calendar.getInstance();
-
SimpleDateFormart
- SimpleDateFormart是一个以与语言环境有关的方式来格式化和解析日期的具体类
- 进行格式化(日期转文本),解析(文本转日期)
SimpleDateFormart sdf = new SimpleDateFormart("yyyy-MM-dd HH:mm:ss"); Date date = new Date(); String d = sdf.formart(date);
-
System
- 系统类,主要用于获取系统的属性数据和其他操作,构造方法私有
12. 集合框架
-
概念
- 对象的容器,定义了多个对象进行操作的常用方法,可实现数组的功能
- 和数组的区别
- 数组长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型,集合只能存储引用类型
- 如果向集合中添加基本数据类型,将会自动完成装箱,生成基本类型的对应包装类
-
Collection体系集合
- 特点
- 层次结构的跟接口
- 代表一组任意类型的对象,无序、无下标、不能重复
- 常用方法
- add:添加一个对象到集合中
- addAll:将一个集合的所有对象添加到此集合中
- clear:清空集合的所有对象
- contains:检查集合中是否包含对象
- equals:比较集合是否与指定对象相等
- isEmpty:判断集合是否为空
- remove:移除集合中的指定对象
- size:返回集合中元素的数量
- toArray:将集合转换成数组
- iterator:返回在此集合的元素进行迭代的迭代器
Collection collection = new ArrayList(); collection.add("Hello"); collection.remove("Hello"); collection.clear(); collection.size(); for(Object obj : collection){ System.out.println(obj); } //在迭代过程中不允许使用Collection移除方法 Iterator item = collection.iterator(); while(item.hasNext()){ item.remove(); System.out.println(item.next()); } collection.contains("Hello");
- 特点
-
List
- 特点:有序、有下标、元素可以重复
- 继承Collection所有的迭代器,但是List有自己的迭代器ListIterator
- ListIterator:列表迭代器,允许程序员按任意方向遍历列表,迭代期间可添加、修改、删除元素
List list = new ArrayList(); list.add("Hello"); ListIterator iterator = list.listIterator(); //从前往后 while(iterator.hasNext()){ int index = iterator.nextIndex(); Object item = iterator.next(); } //从后往前 while(iterator.hasNext()){ int index = iterator.previousIndex(); Object item = iterator.previous(); }
- List实现类
- ArrayList
- 数组结构实现,查询快、增删慢
- JDK1.2版本,运行效率快,线程不安全
- 特点
- 向集合中添加元素后默认容量为10,没有向集合中添加元素默认容量为0
- elmentData:存放元素的数组
- add:
ArrayList arrayList = new ArrayList(); Iterator iterator = arrayList.iterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } ListIterator iterator = arrayList.listIterator(); while(iterator.hasNext()){ System.out.println(iterator.next()); } while(iterator.hasPrevious()){ System.out.println(iterator.previous()); }
- Vector
- 数组结构实现,查询快、增删慢
- JDK1.0版本,运行效率慢、线程安全
- LinkedList
- 链表结构实现,增删快、查询慢
- ArrayList
-
泛型
- 概念
- 泛型类
- 泛型接口
- 泛型方法
- 方法集合
-
Set
-
HashSet
-
TreeSet
-
Map
-
HashMap
-
TreeMap
-
Collection工具类