Java基础
走进Java
Java的诞生
C / C艹
- 1972年C诞生
- 贴近硬件,运行极快,效率极高
- 操作系统,编译器,数据库,网络系统等
- 指针和内存管理
- 1982年C艹诞生
- 面向对象
- 兼容C
- 图形领域、游戏等
我们要建立一个新的语言
- 语法有点像C
- 没有指针
- 没有内存管理
- 真正的可移植性,编写一次,到处运行
- 面向对象
- 类型安全
- 高质量的类库
- …
Java 初生
-
1995年的网页简单而粗糙,缺乏互动性
-
图形界面的程序(Applet)
-
Bill Gates:这是迄今为止设计的最好的语言
-
Java 2 标准版(J2SE):桌面
-
Java 2 移动版(J2ME):手机
-
Java 2 企业版(J2EE):服务器
Java 发展
-
基于Java开发了巨多的平台、系统、工具
- 构建工具:Ant、Maven、Jekins
- 应用服务器:Tomcat、Jetty、Jboss、Websphere、weblogic
- Web开发:Struts、Spring、Hibernate
- 开发工具:Eclipse、intellij idea
- …
-
2006: Hadoop(大数据)
-
2008:Android
Java的特性和优势
- 简单性
- 面向对象
- 可移植性
- 高性能
- 分布式
- 动态性
- 多线程
- 安全性
- 健壮性
环境搭建
1、官网下载jdkJava Downloads | Oracle
下载好后安装,记住安装位置
2、配置环境变量
新建系统环境变量JAVA_HOME,值为JDK的安装位置
Path中添加 %JAVA_HOME%\bin
配置好后,控制台输入 java -version 显示版本信息即为成功
3、下载IntelliJ IDEA
官网:IntelliJ IDEA – the Leading Java and Kotlin IDE (jetbrains.com)
基础语法
Hello World
- 新建文件夹,存放代码
- 新建一个Java文件
- 文件后缀名为.java
- Main.java
- 编写代码
public class Main {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
- 使用javac命令编译 .java文件,会生成一个class文件
- 运行class文件,java class文件,可以看到控制台输出hello world
可能会遇到的情况
- Java是大小写敏感的
- 使用英文;
- 文件名和类名必须保证一致,并且首字母大写
使用idea创建一个新项目
创建一个类
psvm
sout
控制台输出 helloworld
注释、标识符、关键字
注释
- 单行 //
- 块 /* */
- 文档 /** */
public class HelloWorld {
public static void main(String[] args) {
//单行注释
//输出一个HelloWorld
/*
块注释
块注释
*/
// JavaDoc:文档注释 /** */
/**
* @Description HelloWorld
* @Author Aoba
*/
}
}
关键字
标识符
Java所有的组成部分都需要名字。类名、变量名、方法名都被称为标识符。
要求:
所有标识符都应该以字母、$、_开始
首字母之后可以是字母、$、_、数字
不能使用关键字作为变量名或方法名
标识符是大小写敏感的
不建议使用中文名和拼音
合法举例:age 、$name、 _name
非法举例: 123abc、 -name 、 #abc
数据类型
强类型语言
所有变量必须先定义后才能使用
安全性高
速度慢
弱类型语言
VB、 JS
Java的数据类型分为两大类
基本类型:
- 4 种整型 int、short、long、byte
- 2 种浮点型 float、 double
- 1 种表示 Unicode 编码字符的类型(字符型) char
- 1 种表示真值的类型 boolean
public class Demo01 {
public static void main(String[] args) {
int num1 = 10; //4字节
byte num2 = 20; //1字节
short num3 = 30; //2字节
long num4 = 40L;//long类型在数字后面加L 8字节
float num5 = 50.1F;//float类型加F 4字节
double num6 = 3.14;//8字节
char name = 'A';//2字节
boolean flag = true;//1
System.out.println(10);
System.out.println(num1);
//整数拓展: 进制 二进制0b 十进制 八进制0 十六进制0x
int i1 = 10;
int i2 = 0b10;
int i3 = 010;
int i4 = 0x10;
//浮点数拓展:不精确、舍入误差
//BigDecimal(数学工具类)
//最好完全避免使用浮点数进行比较
float f = 0.1F;
double d = 1.0/10;
System.out.println(f == d);//flase
System.out.println(f);
System.out.println(d);
float d1 = 2321313131313133f;
float d2 = d1 + 1;
System.out.println(d1==d2);//true
//字符拓展:
char c1 = 'a';
char c2 = '中';
System.out.println((int)c1);//强制转换
System.out.println((int)c2);
//所有的字符本质还是数字
//编码 Unicode表 2字节 0 - 65536
// U0000 UFFFF
char c3 = '\u0061';
System.out.println(c3);
//转义字符
// \t 制表符Tab
// \n 换行
//...
// 字符串 String是一个类
String sa = new String("hello");
String sb = new String("hello");
String sc = "hello";
String sd = "hello";
System.out.println(sa==sb);//false
System.out.println(sc==sd);//true
//对象 从内存分析
}
}
引用类型
类、接口、数组
单位换算
位(bit)
字节(byte)
1B=8bit;
1KB=1024B
1M=1024KB
1G=1024M
1T=1024G
类型转换
由于Java是强类型语言,所以要进行有些运算的时候,要用到类型转换
低————————————————————>高
byte,short,char -> int -> long -> float -> double
运算中,不同类型的数据先转换成同一类型,然后再进行计算
强制类型转换
自动类型转换
public class Demo02 {
public static void main(String[] args) {
int i = 128;
//强制转换 (类型)变量名 高---->低
byte b = (byte)i;//内存溢出
//自动转换 低---->高
double d = i;
System.out.println(i);
System.out.println(b);
System.out.println(d);
/*注意点
1.不能对布尔值进行转换
2.不能把对象类型转换为不相干的类型
3.把高容量转换到低容量的时候,强制转换
4.转换的时候可能存在内存溢出,或者精度问题
*/
System.out.println((int)23.7);
System.out.println((int)-45.89f);
char c = 'a';
int i1 = c+1;
System.out.println(i1);
System.out.println((char)i1);
//操作比较大的数的时候,注意溢出问题
//JDK7新特性,数字之间可以用下划线分割
int money = 10_0000_0000;
int years = 20;
int total = money*years;
long total2 = money*years;//int*int计算完才转换成long,转换之前已经存在问题了
long total3 = money*((long)years);//正确操作:先把一个数转换成为long
System.out.println(total);
System.out.println(total2);
System.out.println(total3);
}
}
变量、常量、作用域
变量
-
变量就是可以变化的量
-
Java是一种强类型语言,每个变量必须声明其类型。
-
Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域。
-
注意事项:
- 每个变量都有类型,可以是基本类型,也可以是引用类型
- 变量名必须是合法的标识符
- 每一个声明以分号结束
作用域
- 类变量
- 实例变量
- 局部变量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dyFnSwMi-1681821270755)(./assets/22.jpg)]
public class Demo03 {
//类变量 static 从属于类
static double salary = 2500;
//属性
//实例变量:从属于对象,如果不初始化,则为默认值0 0.0 false
//除了基本类型,其余的默认值为null
String name;
int age;
//main 方法
public static void main(String[] args) {
//局部变量:使用前必须声明和初始化值
//int a,b,c;
char x = 'X';
double pi = 3.14;
Demo03 d3 = new Demo03();
System.out.println(d3.age);//输出0
System.out.println(d3.name);//null
//类变量 static
System.out.println(salary);
}
//其他方法
public void add(){
}
}
常量
- 初始化之后不能再改变值
- 常量名一般使用大写字符
public class Demo04 {
//修饰符不存在先后顺序
static final double PI = 3.14;
final static int AGE = 10;
public static void main(String[] args) {
System.out.println(PI);
System.out.println(AGE);
}
}
命名规范
- 所有变量、方法、类名:见名知意
- 类成员变量:首字母小写+驼峰原则:monthSalary
- 局部变量:首字母小写+驼峰原则
- 常量:大写字母+下划线:MAX_VALUE
- 类名:首字母大写+驼峰原则:GoodMan
- 方法名:首字母小写+驼峰原则:runRun()
运算符
- 算术运算符:+ - * / % ++ –
- 赋值运算符:=
- 关系运算符:> < >= <= == != instanceof
- 逻辑运算符:&& || !
- 位运算符: & | ^ ~ >> << >>>
- 条件运算符:?:
- 扩展赋值运算符:+= -= *= /=
测试代码
public class Demo05 {
public static void main(String[] args) {
//二元运算符
//ctrl + d 复制当前行到下一行
int a = 10;
int b = 20;
int c = 30;
int d = 40;
System.out.println(a+b);
System.out.println(a-b);
System.out.println(a*b);
System.out.println(a/(double)b);
long a1 = 1221435354;
int a2 = 122;
short a3 = 50;
byte a4 = 10;
//操作数中有一个为long,结果类型也为long
//没有long,结果都为int
//有一个数为double,结果类型也为double
System.out.println(a1+a2+a3+a4);//long
System.out.println(a2+a3+a4);//int
System.out.println(a3+a4);//int
//关系运算符返回的结果: 布尔值
int b1 = 10;
int b2 = 20;
System.out.println(b1>b2);
System.out.println(b1<b2);
System.out.println(b1==b2);
System.out.println(b1!=b2);
//取余 模运算
int c1 = 21;
System.out.println(c1%10);
//++ --自增,自减 一元运算符
//与c++相同
int num = 3;
int num1 = num++;//先赋值,再自增
int num2 = ++num;//先自增,再赋值
System.out.println(num);
System.out.println(num1);
System.out.println(num2);
//幂运算 很多运算会使用工具类来操作
System.out.println(Math.pow(2,3));
//逻辑运算符
//与或非
boolean d1 = true;
boolean d2 = false;
System.out.println("d1 &&d2:"+(d1 && d2));
System.out.println("d1 || d2:"+(d1 || d2));
System.out.println("!(d1 && d2):"+(!(d1 && d2)));//取反
//短路运算
int d3 = 5;
boolean d4 = (d3<4) && (d3++<4);
System.out.println(d3);
System.out.println(d4);
//位运算
/*
A = 0011 1100
B = 0000 1101
A&B 0000 1100
A|B 0011 1101
A^B 0011 0001 异或
~B 1111 0010 取反
问题:2*8怎么运算最快? 使用位运算 效率极高!
2*8 = 16 2*2*2*2
<<左移 相当于*2
>>右移 相当于/2
0000 0000 0
0000 0001 1
0000 0010 2
0000 0011 3
0000 0100 4
0000 1000 8
0001 0000 16
*/
System.out.println(2<<3);
//+= -=
int e = 10;
int f = 20;
e += f;
e -= f;
System.out.println(e);
//字符串连接符 + ,String 出现String类型会把其他操作数都转换成String连接
System.out.println(e+f);
System.out.println(""+e+f);//1020
System.out.println(e+f+"");//30
//三元运算符?:
//x?y:z
//如果x==true,则结果为y,否则为z
}
}
包机制、JavaDoc
包机制
- 为了更好地组织类,Java提供了包机制,用于区别类名的命名空间
- 一般利用公司的域名倒置作为包名:www.baidu.com ->com.baidu.www
- package club.aoba.www
- import club.aoba.www.* 通配符,导入此包下所有的类‘
JavaDoc
javadoc命令是用来生成自己API文档的,使用方式:使用命令行在目标文件所在目录输入javadoc +文件名.java。
在线api文档:Overview (Java SE 18 & JDK 18) (oracle.com)
签 | 说明 | JDK 1.1 doclet | 标准doclet | 标签类型 |
---|---|---|---|---|
@author 作者 | 作者标识 | √ | √ | 包、 类、接口 |
@version 版本号 | 版本号 | √ | √ | 包、 类、接口 |
@param 参数名 描述 | 方法的入参名及描述信息,如入参有特别要求,可在此注释。 | √ | √ | 构造函数、 方法 |
@return 描述 | 对函数返回值的注释 | √ | √ | 方法 |
@deprecated 过期文本 | 标识随着程序版本的提升,当前API已经过期,仅为了保证兼容性依然存在,以此告之开发者不应再用这个API。 | √ | √ | 包、类、接口、值域、构造函数、 方法 |
@throws异常类名 | 构造函数或方法所会抛出的异常。 | √ | 构造函数、 方法 | |
@exception 异常类名 | 同@throws。 | √ | √ | 构造函数、 方法 |
@see 引用 | 查看相关内容,如类、方法、变量等。 | √ | √ | 包、类、接口、值域、构造函数、 方法 |
@since 描述文本 | API在什么程序的什么版本后开发支持。 | √ | √ | 包、类、接口、值域、构造函数、 方法 |
{@link包.类#成员 标签} | 链接到某个特定的成员对应的文档中。 | √ | 包、类、接口、值域、构造函数、 方法 | |
{@value} | 当对常量进行注释时,如果想将其值包含在文档中,则通过该标签来引用常量的值。 | √(JDK1.4) | 静态值域 |
此外还有@serial、@serialField、@serialData、{@docRoot}、{@inheritDoc}、{@literal}、{@code} {@value arg}几个不常用的标签,由于不常使用,我们不展开叙述。
使用idea生成javadoc文档
代码 使用文档注释
package club.aoba.www;
import java.util.Date;
/**
* @author Aoba
* @version 1.0.0
* */
public class Aoba {
Date date;
}
点击上方tools 选择生成文档位置
查看自己的api文档
流程控制
用户交互Scanner
我们可以通过Scanner类 来获取用户的输入
基本语法:Scanner scanner = new Scanner(System.in);
next()
阻塞
不能得到带有空格的字符串
nextLine()
阻塞
以Enter为结束符,返回输入回车之前的所有字符
可以获得空格
hasNext()
hasNextLine()
package club.aoba.www;
import java.util.Scanner;
public class Demo06 {
public static void main(String[] args) {
//创建一个扫描器对象,用于接收键盘数据
Scanner scanner = new Scanner(System.in);
System.out.println("使用next方式接收");
//判断用户有没有输入字符串
if(scanner.hasNext())
{
//使用next方式接收
String str = scanner.next();
System.out.println("输出的内容为:"+str);
}
System.out.println("使用nextLine方式接收");
if(scanner.hasNextLine())
{
String str = scanner.nextLine();
System.out.println("输出的内容为:"+str);
}
System.out.println("请输入数据:");
String str = scanner.nextLine();
System.out.println("输出的内容为:"+str);
int i = 0;
float f = 0.0f;
System.out.println("请输入整数:");
if(scanner.hasNextInt())
{
i = scanner.nextInt();
System.out.println(i);
}
else
{
System.out.println("你输入的不是整数");
}
System.out.println("请输入小数:");
if(scanner.hasNextFloat())
{
f = scanner.nextFloat();
System.out.println(f);
}
else
{
System.out.println("你输入的不是小数");
}
//凡是属于IO流的类如果不关闭会一直占用资源
//用完就关掉
scanner.close();
}
}
顺序结构
Java的基本结构就是顺序结构,除非特别指明,否则就按顺序一句一句执行。
顺序结构是最简单的算法结构。
它是任何一个算法都离不开的一种基本算法结构。
public class Demo07 {
public static void main(String[] args) {
System.out.println("hello1");
System.out.println("hello2");
System.out.println("hello3");
System.out.println("hello4");
System.out.println("hello5");
}
}
选择结构
if单选择结构
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容:");
String s = scanner.nextLine();
//equals:判断字符串是否相等
if(s.equals("Hello"))
{
System.out.println(s);
}
System.out.println("end");
scanner.close();
if双选择结构
Scanner scanner = new Scanner(System.in);
System.out.println("请输入成绩:");
int score = scanner.nextInt();
if(score > 60) {
System.out.println("及格");
}
else {
System.out.println("不及格");
}
scanner.close();
if多选则结构
Scanner scanner = new Scanner(System.in);
System.out.println("请输入成绩:");
int score = scanner.nextInt();
if(score == 100){
System.out.println("恭喜满分!");
}else if(score < 100 && score >= 90){
System.out.println("A级");
}else if(score < 90 && score >= 80){
System.out.println("B级");
}else if(score < 80 && score >= 70){
System.out.println("C级");
}else if(score < 70 && score >= 60){
System.out.println("D级");
}else if(score <60 && score >= 0){
System.out.println("不及格!");
} else{
System.out.println("成绩不合法!");
}
scanner.close();
嵌套的if结构
随便嵌套啊~
switch多选结构
switch语句中,变量类型可以是byte、short、int或者char
从Java SE7开始,switch支持字符串String类型了
case标签必须是字符串常量,或字面量
package club.aoba.www;
public class Demo09 {
public static void main(String[] args) {
char grade = 'C';
//switch 匹配一个具体的值
// 不写break:case穿透
switch (grade) {
case 'A':
System.out.println("优秀!");
break;
case 'B':
System.out.println("良好!");
break;
case 'C' :
System.out.println("及格!");
break;
case 'E':
System.out.println("再接再厉!");
break;
case 'F':
System.out.println("挂科!");
break;
//默认
default:
System.out.println("未知等级!");
}
}
}
循环结构
while循环
只要布尔表达式为true,循环就会一直执行下去
我们大多数情况是会让循环停止下来的,我们需要一个让表达式失效的方式来结束循环
少部分情况需要循环一直执行,比如服务器的请求响应监听等
循环条件一直为true会造成死循环,应尽量避免。
package club.aoba.www;
public class Demo10 {
public static void main(String[] args) {
//输出1~100
int i = 0;
while(i < 100)
{
i++;
System.out.println(i);
}
}
}
//死循环
while(true)
{
//...
}
do…while循环
对于while语句而言,如果不满足条件,则不会进入循环。
但有时候我们需要即使不满足条件,也要是少执行一次。
do…while循环至少会执行一次
int j = 0;
int sum = 0;
do{
sum = sum + j;
j++;
}while(j <= 100);
System.out.println(sum);
for循环
for循环语句是支持迭代的一种通用结构,是最有效、最灵活的循环结构
for循环执行的此时是在执行前就确定的
package club.aoba.www;
public class Demo11 {
public static void main(String[] args) {
int a = 1;//初始化条件
while(a <= 100)//条件判断
{
System.out.println(a);//循环体
a+=2;//迭代
}
System.out.println("while循环结束");
//初始化 条件判断 迭代
for(int i = 1; i <= 100; i+=2)
{
System.out.println(i);
}
System.out.println("for循环结束");
//快捷写法:100.for
//死循环
//for (; ; ) {
//
//}
//计算0~100奇数和偶数的和
int oddSum = 0;//奇数
int evenSum = 0;//偶数
for (int i = 0; i <= 100; i++) {
if(i%2!=0) {
oddSum+=i;
}else{
evenSum+=i;
}
}
System.out.println("奇数的和:"+oddSum+"偶数的和:"+evenSum);
//输出1~1000之间能被5整除的数,每行输出3个
for (int i = 0; i <= 1000; i++) {
if(i%5 == 0){
System.out.print(i+"\t");
}
if(i%(5*3) == 0){
System.out.println();
}
}
//println 输出完会换行
//print 输出完不会换行
}
}
打印99乘法表
package club.aoba.www;
public class Demo12 {
public static void main(String[] args) {
for (int j = 1; j <= 9; j++) {
for (int i = 1; i <= j; i++) {
System.out.print(j + "*" + i + "=" + (j*i) + "\t");
}
System.out.println();
}
}
}
增强for循环
Java5引入了一种主要用于数组或集合的增强型for循环
package club.aoba.www;
public class Demo13 {
public static void main(String[] args) {
int[] numbers = {10, 20, 30, 40, 50};//定义了一个数组
for (int i = 0; i < 5; i++) {
System.out.println(numbers[i]);
}
//遍历数组的元素
for(int x:numbers){
System.out.println(x);
}
}
}
break
强行退出循环,不执行循环中的剩余语句
continue
终止某次循环过程,跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定
goto
尽管goto是Java的一个保留字,但并未在语言中得到正式使用
可以在break和continue上加标签
对Java来说,唯一用到标签的地方是在循环语句之前
唯一理由是:我们希望在其中嵌套另一个循环,由于break和continue只能中断当前循环,但若同标签使用,他们就会中断到标签在的地方
package club.aoba.www;
public class Demo14 {
public static void main(String[] args) {
//打印101~150之间所有的质数
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;
}
}
System.out.print(i+" ");
}
}
}
练习
学习c语言时做过的练习可以用java再实现一遍
方法详解
什么是方法
简单理解:就是写到了类里的函数
System.out.print();
public final class System {
//......
public static final PrintStream out = null;
//......
}
public class PrintStream extends FilterOutputStream
implements Appendable, Closeable
{
//......
public void println() {
newLine();
}
//......
}
-
Java方法是语句的集合,他们在一起执行一个功能
-
方法是解决一类问题的步骤的有序组合
-
方法包含于类或对象中
-
方法在程序中被创建,在其他地方被引用
-
-
设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,就是一个方法只完成一个功能,这样利于我们后期扩展。
-
方法命名规则:首字母小写+驼峰原则:runRun()
package club.aoba.www;
public class Demo15 {
public static void main(String[] args) {
Demo15 test = new Demo15();
System.out.println(test.add(12, 45));
}
//加法
public int add(int a, int b){
return a+b;
}
}
方法的定义和调用
定义
Java的方法类似于其他语言的函数,是用一段用来完成特定功能的代码片段,一般情况下,定义一个方法包含以下语法:
方法包含一个方法头和方法体
修饰符:可选,定义了该方法的访问类型
返回值类型:没有返回值void
方法名:是方法的实际名称。方法名和参数表共同构成方法签名
参数类型:可选,形参:在方法被调用时,用于接收外界输入的数据;实参:调用方法时实际传给方法的数据
方法体:包含具体的语句,定义了该方法的功能
返回值:return
修饰符 返回值类型 方法名(参数类型 参数名){
...
方法体
...
return 返回值
}
调用
对象.方法(实参列表)
当方法返回一个值时:方法调用通常被当做一个值
返回值为void:方法调用一定是一条语句
package club.aoba.www;
public class Demo16 {
public static void main(String[] args) {
System.out.println(max(10, 20));
}
//比大小
public static int max(int num1, int num2){
if(num1 > num2){
return num1;//返回结果,终止方法
}
else {
return num2;
}
}
}
课后:值传递(Java)地址传递 引用传递
方法重载
重载就是在一个类中,有相同的函数名称,但形参不同的函数。
方法的重载的规则:
- 方法名称必须相同。
- 参数列表必须不同(个数不同、或类型不同、参数排列顺序不同等)。
- 方法的返回类型可以相同也可以不相同。
- 仅仅返回类型不同,不足以成为方法的重载。
实现理论:
方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
package club.aoba.www;
public class Demo16 {
public static void main(String[] args) {
System.out.println(max(10, 20));
System.out.println(max(10.0, 20.0));
}
//比大小
public static int max(int num1, int num2){
if(num1 > num2){
return num1;//返回结果,终止方法
}
else {
return num2;
}
}
public static double max(double num1, double num2){
if(num1 > num2){
return num1;//返回结果,终止方法
}
else {
return num2;
}
}
}
应用举例
命令行传参
有时候你希望程序运行的时候在传递给他消息。
这要靠传递命令行参数给main()实现
package club.aoba.www;
public class Demo17 {
public static void main(String[] args) {
for(int i = 0; i < args.length; i++)
{
System.out.println(args[i]);
}
}
}
可变参数
JDK 1.5开始,Java支持传递同类型的可变参数给一个方法。
在方法声明中,在指定参数类型后加一个省略号(.…)。
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
package club.aoba.www;
public class Demo18 {
public static void main(String[] args) {
Demo18 demo18= new Demo18();
demo18.printMax(34, 3, 3, 2, 56.5);
demo18.printMax(new double[]{1, 2, 3});
}
public void printMax(double... numbers){
if(numbers.length == 0)
{
System.out.println("没有任何参数!");
return;
}
double result = numbers[0];
for(int i = 1; i <numbers.length; i++){
if(numbers[i] > result)
{
result = numbers[i];
}
}
System.out.println(result);
}
}
递归
- A方法调用B方法,我们很容易理解!
- 递归就是:A方法调用A方法!就是自己调用自己
- 利用递归可以用简单的程序来解决一些复杂的问题。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。
- 递归结构包括两个部分:
递归头:什么时候不调用自身方法。如果没有头,将陷入死循环。
递归体:什么时候需要调用自身方法。
package club.aoba.www;
public class Demo19 {
public static void main(String[] args) {
System.out.println(f(5));
}
//阶乘
public static int f(int n){
if (n == 1){
return 1;
}else{
return n*f(n-1);
}
}
}
数组详解
定义
相同类型数据的有序集合
每一个数据称做一个数组元素,通过下标访问
声明和创建
package club.aoba.www;
public class Demo20 {
public static void main(String[] args) {
int[] nums;//定义:声明一个数组
int nums2[];//效果相同,但不是首选方法
nums = new int[10];//创建一个数组,可以存放10个int类型的数字
int[] ints = new int[10];
//给数组元素赋值
for (int i = 0; i < nums.length; i++) {
nums[i] = i + 1;
}
//遍历
//不赋值默认值0
for (int i = 0; i < nums.length; i++) {
System.out.println(nums[i]);
}
}
}
内存分析
堆:此内存区域唯一的目的就是存放对象实例,new出来的东西
栈:存放基本数据类型(具体数值)、对象引用类型(不等同于对象本身)(具体地址)
方法区:线程共享,存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据
// 声明数组 // 创建数组 // 赋值
int[] array = null; array = new int[10]; array[0] = 0;array[1] = 1;//......
三种初始化
package club.aoba.www;
public class Demo21 {
public static void main(String[] args) {
//静态初始化
int [] a = {1, 2, 3,4};
//动态初始化:包含默认初始化
int [] b = new int[10];
}
}
四个基本特点
1、其长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
2、其元素必须是相同类型,不允许出现混合类型。
3、数组中的元素可以是任何数据类型,包括基本类型和引用类型。
4、数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。
数组边界
下标的合法区间:0~length-1,越界则报错
使用
package club.aoba.www;
public class Demo22 {
public static void main(String[] args) {
int [] arrays = {1, 2, 3, 4, 5};
//打印全部的数组元素
for (int i = 0; i < arrays.length; i++) {
System.out.println(arrays[i]);
}
//计算总和
int sum = 0;
for (int i = 0; i < arrays.length; i++) {
sum = sum + arrays[i];
}
System.out.println(sum);
//查找最大元素
int max = arrays[0];
for (int i = 1; i < arrays.length; i++) {
if(arrays[i] > max)
max = arrays[i];
}
System.out.println(max);
//jdk1.5 没有下标
for (int array : arrays) {
System.out.println(array);
}
//数组做参数
printArr(arrays);
int [] reverse = reverse(arrays);
printArr(reverse);
}
//打印数组元素
public static void printArr(int[] arrays)
{
for (int i = 0; i < arrays.length; i++) {
System.out.print(arrays[i]+" ");
}
}
//反转数组
public static int[] reverse(int [] arrays){
int[] result = new int[arrays.length];
for (int i = 0, j = arrays.length-1; i <arrays.length ; i++, j--) {
result[j] = arrays[i];
}
return result;
}
}
多维数组
package club.aoba.www;
public class Demo23 {
public static void main(String[] args) {
int[][] array = {{1, 2}, {2, 3}, {3, 4}, {4, 5}};
printArr(array[0]);
System.out.println(array[0][0]);
System.out.println(array[0][1]);
System.out.println(array.length);
System.out.println(array[0].length);
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.println(array[i][j]);
}
}
}
//打印数组元素
public static void printArr(int[] arrays)
{
for (int i = 0; i < arrays.length; i++) {
System.out.print(arrays[i]+" ");
}
}
}
初识面向对象
什么是面向对象
Java的核心思想就是OOP(Object Oriented Programming)
面向过程&面向对象
什么是面向对象
本质:以类的方式组织代码,以对象的形式封装数据
-
抽象 —> 把具有相同形象的东西抽取出来
-
三大特性:封装、继承、多态
从认识的角度考虑是先有对象后有类。对象是具体的事物。类是抽象的,是对 对象 的抽象。
从代码运行的角度考虑是先有类后有对象。类是对象的模板。
类与对象的创建
创建与初始化对象
package club.aoba.oop;
//学生类
public class Student {
//属性:字段
String name;//null
int age;//0
//方法
public void study(){
System.out.println(this.name+"在学习");
}
}
package club.aoba.oop;
//一个项目应该只有一个main方法
public class Application {
public static void main(String[] args) {
//类:抽象的,实例化
//类实例化后会返回一个自己的对象
//xiaoming对象就是Student类的具体实例
Student xiaoming = new Student();
Student xiaohong = new Student();
xiaoming.name = "小明";
xiaoming.age = 3;
System.out.println(xiaoming.name);
System.out.println(xiaoming.age);
System.out.println(xiaohong.name);
System.out.println(xiaohong.age);
}
}
构造器详解
package club.aoba.oop;
public class Person {
String name;
int age;
//实例化初始值
//使用new关键字,本质是在调用构造器,用来初始化值
//存在默认构造器
public Person(){}
//显式定义构造器:定义后默认的构造器失效
//有参构造:
public Person(String name){
this.name = name;
}
//Person person = new Person("名字");
//alt + insert快捷生成构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
package club.aoba.oop;
//一个项目应该只有一个main方法
public class Application {
public static void main(String[] args) {
//实例化对象
Person person = new Person();
System.out.println(person.name);
}
}
封装
- 该露的露,该藏的藏
- 我们程序设计要追求高内聚,低耦合。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合就是仅暴露少量的方法给外部使用。
- 封装(数据的隐藏)
- 通常,应禁止直接访问一个对象中数据的实际表示,而应该通过操作接口来访问,这称为信息的隐藏
- 属性私有,get/set
package club.aoba.oop;
//学生类
public class Student {
//属性私有
private String name;//null
private int id;
private int age;//0
private char sex;
//提供一些可以操作这些属性的方法
//提供一些public的get set方法
public String getName(){
return this.name;
}
public void setName(String name){
this.name = name;
}
//alt + insert 自动生成get set 方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age > 120 || age < 0)
return;
this.age = age;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public void study(){
System.out.println(this.name+"在学习");
}
}
package club.aoba.oop;
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("aoba");
System.out.println(s1.getName());
}
}
继承
- 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模
- extends的意思是扩展。子类是父类的扩展。
- Java中类只有单继承,没有多继承!一个子类只能继承一个基类,一个基类可以被多个子类继承。
- 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
- 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类用关键字extends来表示。
- 子类和父类之间,从意义上讲具有“is a”的关系
- object类
- super
package club.aoba.oop1;
//基类,父类
//Java中所有的类都默认直接或间接继承object类
public class Person {
//public
//protected
//default(默认什么都不写)
//private无法被继承
//重写了有参构造,一定要把无参构造写出来
public Person(){
System.out.println("Person构造器");
}
public Person(String name) {
this.name = name;
}
protected String name = "Aoba";
private int money = 10000;
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
public void say(){
System.out.println("say person");
}
}
package club.aoba.oop1;
//student is a person
//派生类,子类
public class Student extends Person{
//ctrl + h查看继承
public Student() {
//隐藏代码:调用了父类的无参构造
super();//调用父类的构造器,必须要在子类构造器的第一行
System.out.println("Student构造器");
}
private String name = "aoba";
public void test(String name){
System.out.println(name);//参数
System.out.println(this.name);//当前类
System.out.println(super.name);//父类
}
public void say(){
System.out.println("say student");
}
public void test1(){
say();
this.say();
super.say();
}
}
package club.aoba;
import club.aoba.oop1.Person;
import club.aoba.oop1.Student;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.say();
//System.out.println(student.money);
Person person = new Person();
student.test("青叶");
student.test1();
}
}
方法重写
package club.aoba.oop1;
//重写都是方法的重写,和属性无关
public class B {
public static void test(){
System.out.println("B");
}
public void test1(){
System.out.println("B");
}
}
package club.aoba.oop1;
public class A extends B{
public static void test(){
System.out.println("A");
}
//重写
//需要有继承关系子类重写父类的方法
//方法名必须相同
//参数列表必须相同
//修饰符:范围可以扩大但不能缩小
//抛出的异常:可以被缩小但不能扩大
@Override//注解:有功能的注释
public void test1() {
System.out.println("A");
}
//为什么需要重写?
//父类的功能子类不一定需要,或者不一定满足
//alt + insert
}
package club.aoba;
import club.aoba.oop1.A;
import club.aoba.oop1.B;
public class Application {
public static void main(String[] args) {
//静态方法的调用只跟左边,定义的数据类型有关
//非静态public:重写
A a = new A();
a.test();//A
//父类的引用指向子类
B b = new A();
b.test();//B
b.test1();//A 子类重写了父类的方法
}
}
多态
- 动态编译:类型:可扩展性
- 即同一方法可以根据发送对象的不同而采用多种不同的行为方式
- 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多
- 多态存在的条件:有继承关系,子类重写父类的方法,父类引用指向子类对象
- 注意:多态是方法的多态,属性没有多态性
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
多态性是对象多种表现形式的体现。
现实中,比如我们按下 F1 键这个动作:
- 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
- 如果当前在 Word 下弹出的就是 Word 帮助;
- 在 Windows 下弹出的就是 Windows 帮助和支持。
同一个事件发生在不同的对象上会产生不同的结果。
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child();
父类类型 引用名 = new 子类类型();
package club.aoba.oop2;
public class Person {
public void run(){
System.out.println("run");
}
}
package club.aoba.oop2;
public class Student extends Person{
//static,final,private不能重写
@Override
public void run() {
System.out.println("son");
}
public void eat(){
System.out.println("吃");
}
}
package club.aoba;
import club.aoba.oop2.Person;
import club.aoba.oop2.Student;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的
//new Student();
//可以指向的引用类型就不确定了:父类的引用指向子类
//子类能调用的方法:自己的,继承父类的
Student s1 = new Student();
//父类:可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();
Object s3 = new Student();
s2.run();//子类重写了父类的方法:执行子类的方法
s1.run();
}
}
instantof与类型转换
instanceof
instanceof 是 Java 的一个二元操作符
instanceof 是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类或其子类的实例,返回 boolean 的数据类型。
package club.aoba;
import club.aoba.oop2.Person;
import club.aoba.oop2.Student;
import club.aoba.oop2.Teacher;
public class Application {
public static void main(String[] args) {
Object object = new Student();
System.out.println(object instanceof Student);
System.out.println(object instanceof Person);
System.out.println(object instanceof Object);
System.out.println(object instanceof Teacher);
System.out.println(object instanceof String);
Person person = new Student();
System.out.println(person instanceof Student);
System.out.println(person instanceof Person);
System.out.println(person instanceof Object);
System.out.println(person instanceof Teacher);
//System.out.println(person instanceof String);编译报错
Student student = new Student();
System.out.println(student instanceof Student);
System.out.println(student instanceof Person);
System.out.println(student instanceof Object);
//System.out.println(student instanceof Teacher);编译报错
//System.out.println(student instanceof String);编译报错
}
}
类型转换
package club.aoba;
import club.aoba.oop3.Person;
import club.aoba.oop3.Student;
public class Application {
public static void main(String[] args) {
//类型转换:父 子
//高 低
Person obj = new Student();
//高转低要强制转换
((Student)obj).go();
obj.run();
Person obj1 = new Person();
((Student)obj).go();
//低转高自动转换
Student student = new Student();
student.go();
Person person = student;
//person.go(); 子类转换为父类,可能会丢失自己本来的一些方法
}
}
static关键字
package club.aoba.oop4;
public class Student {
private static int age;//静态变量 多线程
private double score;//非静态变量
public void run(){
go();
}
public static void go(){
}
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(Student.age);
System.out.println(s1.age);
System.out.println(s1.score);
Student.go();
go();
}
}
package club.aoba.oop4;
//被final修饰则不能被继承
public final class Person {
//2 赋初始值
{
//匿名代码块
System.out.println("匿名代码块");
}
//1 只执行一次
static{
//静态代码块
System.out.println("静态代码块");
}
//3
public Person() {
System.out.println("构造器");
}
public static void main(String[] args) {
Person person1 = new Person();
System.out.println();
Person person2 = new Person();
}
}
package club.aoba.oop4;
//静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
System.out.println(random());
System.out.println(PI);
}
}
抽象类
- abstract修饰符可以用来修饰方法,也可以修饰类。得到抽象方法和抽象类
- 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类
- 抽象类,不能使用new关键字来创建对象,它是用来让子类继承的
- 抽象方法,只有方法的声明,没有方法的实现,他是用来让子类实现的
- 子类继承抽象类,那么就必须实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类
package club.aoba.oop5;
//abstract 抽象类
public abstract class Action {
//约束 想要有人帮我们实现
//抽象方法,只有声明,没有实现
public abstract void doSomething();
//不能new出来,只能靠子类去实现
}
package club.aoba.oop5;
//由子类实现抽象类的方法,除非子类也是抽象类
public class A extends Action{
@Override
public void doSomething() {
}
}
接口
-
生活中的接口最具代表性的就是插座,例如一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,那是因为国外自己定义的接口类型。
-
java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现
-
普通类:只有具体实现
-
抽象类:具体实现和规范(抽象方法)都有
-
接口:只有规范
-
借口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想。
-
接口本质是契约,就像我们人间的法律一样。制定好后大家都遵守
-
oo的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(c++ java c#等),就是因为设计模式所研究的,实际上就是如何合理地去抽象。
-
关键字 interface
package club.aoba.oop6;
//抽象的思维
// interface 定义的关键字,接口都需要有实现类
public interface UserService {
//属性都是常量public static final
//一般不这么用
int AGE = 99;
//接口中的定义的方法都是抽象的public abstract
public abstract void run();
void go(String name);
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
package club.aoba.oop6;
public interface TimeService {
void timer();
}
package club.aoba.oop6;
//类 可以实现接口 一般实现类以Impl结尾 implements实现的意思
//实现了接口的类,就需要重写接口中的方法
//利用接口实现多继承
public class UserServiceImpl implements UserService,TimeService{
@Override
public void run() {
}
@Override
public void go(String name) {
}
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
}
}
内部类
内部类就是在一个类的内部再定义一个类。
- 成员内部类
package club.aoba.oop7;
public class Outer {
private int id = 10;
public void out(){
System.out.println("外部类的方法");
}
public class Inner{
public void in(){
System.out.println("内部类的方法");
}
//获得外部类的私有属性 方法
public void getID(){
System.out.println(id);
}
}
}
package club.aoba;
import club.aoba.oop7.Outer;
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
//通过外部类来实例化内部类
Outer.Inner inner = outer.new Inner();
inner.in();
inner.getID();
}
}
- 静态内部类
package club.aoba.oop7;
public class Outer {
private int id = 10;
public void out(){
System.out.println("外部类的方法");
}
public static class Inner{
public void in(){
System.out.println("内部类的方法");
}
}
}
- 局部内部类
package club.aoba.oop7;
public class Outer {
private int id = 10;
public void out(){
System.out.println("外部类的方法");
}
}
//一个java类中可以有多个class类,但只能有一个public
class A{
public static void main(String[] args) {
}
}
package club.aoba.oop7;
public class Outer {
//局部内部类
public void method(){
class Inner{
}
}
}
- 匿名内部类
package club.aoba.oop7;
public class Test {
public static void main(String[] args) {
//没有名字初始化类
//匿名对象的使用,不用将实例保存到变量中
new Apple().eat();
new UserService(){
@Override
public void hello() {
}
};
}
}
class Apple{
public void eat(){
System.out.println("1");
}
}
interface UserService{
void hello();
}
异常处理
什么是异常
- 实际工作中,遇到的情况不可能是非常完美的。比如:你写的某个模块,用户输入不一定符合你的要求、你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据库的数据,数据可能是空的等。我们的程序再跑着,内存或硬盘可能满了。等等。
- 软件程序在运行过程中,非常可能遇到刚刚提到的这些异常问题,我们叫异常,英文是:Exception,意思是例外。这些,例外情况,或者叫异常,怎么让我们写的程序做出合理的处理。而不至于程序崩溃。
- 异常指程序运行中出现的不期而至的各种状况,如:文件找不到、网络连接失败、非法参数等。异常发生在程序运行期间,它影响了正常的程序执行流程。
- 一些错误示例
package club.exception;
public class Demo01 {
public static void main(String[] args) {
new Demo01().a();
}
public void a(){
b();
}
public void b(){
a();
}
}
Exception in thread "main" java.lang.StackOverflowError
package club.exception;
public class Demo01 {
public static void main(String[] args) {
System.out.println(11/0);
}
}
Exception in thread "main" java.lang.ArithmeticException: / by zero
at club.exception.Demo01.main(Demo01.java:5)
简单分类
- 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
- 运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
- 错误:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
异常体系结构
Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。在Java APl中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception.
Error
- Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
- Java虚拟机运行错误(Virtual MachineError),当JVM不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止;
- 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。
Exception
- 在Exception分支中有一个重要的子类RuntimeException(运行时异常)
- ArraylndexOutOfBoundsException(数组下标越界)
- NullPointerException(空指针异常)
- ArithmeticException(算术异常)
- MissingResourceException(丢失资源)
- ClassNotFoundException(找不到类)等异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。
- 这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生;
- Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
捕获和抛出异常
- 抛出异常
- 捕获异常
- 异常处理五个关键字:try, catch, finally, throw, throws
package club.exception;
public class Test {
public static void main(String[] args) {
int a = 1;
int b = 0;
//监控区域
try{
System.out.println(a/b);
}catch(ArithmeticException e){//捕获异常
System.out.println("程序出现异常,变量b不能为0");
}finally {//处理善后工作
System.out.println("finally");
}
}
}
运行结果:
程序出现异常,变量b不能为0
finally
finally可以不要,假设IO流,资源等需要关闭,可以将关闭的操作放到finally中
package club.exception;
public class Test {
public static void main(String[] args) {
//假设要捕获多个异常:从小到大捕获
//监控区域
try{
new Test().a();
}catch(Error e){//捕获异常 参数为:想要捕获的异常类型 最高的是Throwable
System.out.println("Error");
}catch(Exception e){
System.out.println("Exception");
}catch(Throwable t) {
System.out.println("Throwable");
}finally {//处理善后工作
System.out.println("finally");
}
}
public void a(){b();}
public void b(){a();}
}
package club.exception;
public class Test02 {
public static void main(String[] args) {
//快捷键: Ctrl + Alt + T
try {
System.out.println(11/0);
} catch (Exception e) {
System.exit(0);//手动结束程序
e.printStackTrace();//打印错误的栈信息
throw new RuntimeException(e);//主动抛出异常
} finally {
}
}
}
package club.exception;
public class Test {
public static void main(String[] args) {
try {
new Test().test(1,0);
} catch (ArithmeticException e) {
throw new RuntimeException(e);
}
}
//假设这个方法中处理不了这个异常,我们需要把异常往外抛出去,在方法上抛出异常
public void test(int a, int b) throws ArithmeticException{
if(b == 0){
throw new ArithmeticException();//主动抛出异常,一般在方法中使用
}
System.out.println(a/b);
}
}
自定义异常
使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需要继承Exeception类即可。
在程序中使用自定义异常类,大体可分为以下几个步骤:
- 创建自定义异常类
- 在方法中通过throw关键字抛出异常对象
- 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throw关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
- 在出现异常方法的调用者中捕获并处理异常
package club.exception.test;
//自定义的异常类
public class MyException extends Exception{
//传递数字 大于10 抛出异常
private int detail;
public MyException(int detail) {
this.detail = detail;
}
//异常的打印信息
@Override
public String toString() {
return "MyException{" +
"detail=" + detail +
'}';
}
}
package club.exception.test;
public class Test {
//可能会存在异常的方法
static void test(int a) throws MyException {
System.out.println("传递的参数为:"+a);
if(a>10){
throw new MyException(a);//抛出
}
System.out.println("OK");
}
public static void main(String[] args) {
try {
test(11);
} catch (MyException e) {
System.out.println("MyException "+ e);//此处e即为toString方法
}
}
}
经验总结
- 处理运行异常时,采用逻辑去合理规避同时辅助try-catch处理
- 在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
- 对于不确定的代码,也可以加上try-catch,处理潜在的异常
- 尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出
- 具体如何处理异常,需要根据不同的业务需求和异常类型去决定
- 尽量添加finally语句去释放占用的资源
常用类
包装类
概述
- 基本数据类型所对应的引用数据类型
- Object可统一所有数据,包装类的默认值是null
基本数据类型 | 包装类型 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
装箱和拆箱
使用构造方法装箱已废弃,原因:
It is rarely appropriate to use this constructor. The static factory valueOf(int) is generally a better choice, as it is likely to yield significantly better space and time performance.
使用此构造函数很少合适。valueOf(int)通常是一个更好的选择,因为它可能产生显著更好的空间和时间性能。
package club.often.Demo02;
public class Test {
public static void main(String[] args) {
//装箱:基本类型转成引用类型的过程
Integer int1 = new Integer(10);
Integer int2 = Integer.valueOf(10);
//拆箱:引用类型转成基本类型
int res = int1.intValue();
//jdk1.5之后,提供自动装箱和拆箱
//实际上编译器帮你调用了上述方法
int age = 30;
Integer int3 = age;
int age2 = int3;
}
}
基本类型和字符串之间的转换
需要保证类型兼容
package club.often.Demo02;
public class Test {
public static void main(String[] args) {
//基本类型转成字符串
int n1 =100;
String s1 = n1+" ";
String s2 = Integer.toString(n1);
String s3 = Integer.toString(n1, 16);
System.out.println(s1 + s2 + " " + s3);
//字符串转成基本类型
String string = "150";
int n2 = Integer.parseInt(string);
System.out.println(n2);
//boolean字符串形式转成基本类型: "true"---->true !"true"---->false
String str1 = "true";
String str2 = "aoba";
boolean b1 =Boolean.parseBoolean(str1);
boolean b2 =Boolean.parseBoolean(str2);
System.out.println(b1 + " " + b2);
}
}
Integer缓冲区
- Java预先创建了256个常用的整数包装类型对象
- 在实际应用当中,对已创建的对象进行复用
valueOf()源码
@HotSpotIntrinsicCandidate
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
package club.often.Demo03;
public class Test {
public static void main(String[] args) {
Integer i1 = Integer.valueOf(100);
Integer i2 = Integer.valueOf(100);
System.out.println(i1 == i2);//true
Integer i3 = 100;
Integer i4 = 100;
System.out.println(i3 == i4);//100 为true 自动装箱调用valueOf方法
Integer integer1 = new Integer(100);
Integer integer2 = new Integer(100);
System.out.println(integer1 == integer2);//false
Integer i5 = 200;
Integer i6 = 200;
System.out.println(i5 == i6);//200 为false
}
}
Math 类
Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。
Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用。
代码:
public class Test {
public static void main (String []args)
{
System.out.println("90 度的正弦值:" + Math.sin(Math.PI/2));
System.out.println("0度的余弦值:" + Math.cos(0));
System.out.println("60度的正切值:" + Math.tan(Math.PI/3));
System.out.println("1的反正切值: " + Math.atan(1));
System.out.println("π/2的角度值:" + Math.toDegrees(Math.PI/2));
System.out.println(Math.PI);
}
}
以上实例编译运行结果如下:
90 度的正弦值:1.0
0度的余弦值:1.0
60度的正切值:1.7320508075688767
1的反正切值: 0.7853981633974483
π/2的角度值:90.0
3.141592653589793
String类
概述
- 字符串是常量,创建之后不可改变
- 字符串字面值储存在字符串池中,可以共享
- JDK6.0及之前版本,字符串池在方法区中,7.0以后在堆中
package club.often.Demo04;
public class Test {
public static void main(String[] args) {
String name = "hello";//产生一个对象,"hello"常量存储在字符串池中
name = "aoba";//给字符串赋值时,并没有修改数据,而是重新开辟空间, “hello”就变成垃圾了
String name2 = "aoba";//name 和 name2 指向字符串池中的同一个对象,实现了共享
System.out.println(name == name2);//true
String str = new String("aoba");//在堆和字符串池同时开辟空间出现两个对象,str指向堆里的对象。实际运行时堆里面是没有这个对象的。
//使用这种方法可能会浪费空间
String str2 = new String("aoba");
System.out.println(str == name);//false
System.out.println(str == str2);//false
//所以在比较两个字符串时,用equals方法
System.out.println(str.equals(str2));
}
}
常用方法
package club.often.Demo04;
import java.util.Arrays;
import java.util.Locale;
public class Method {
public static void main(String[] args) {
//length();返回字符串的长度
//charAt(int index);根据下标返回字符
//contains(String str);判断是否包含某个子字符串
//toCharArray():将字符串转成数组
//indexOf(String str):查找str首次出现的下标,不存在返回-1
//lastIndexOf(String str):查找str在当前字符串中最后一次出现的下标
//trim():去掉字符串前后的空格
//toUpperCase():将小写转成大写 toLowerCase():将小写转成大写
//endWith(String str):判断字符串是否以str结尾 stratWitn(String str):开头
//replace(char oldChar, char newChar);将旧字符串替换成新字符串
//split(String str):根据str做拆分
String str = "java是世界上最好的,java编程语言,java";
System.out.println(str.length());
System.out.println(str.charAt(3));
System.out.println(str.contains("java"));
System.out.println(Arrays.toString(str.toCharArray()));
System.out.println(str.indexOf("java"));
System.out.println(str.indexOf("java",4));
System.out.println(str.lastIndexOf("java"));
String str2 = " hello WORLD ";
System.out.println(str2.trim());
System.out.println(str2.toUpperCase());
System.out.println(str2.toLowerCase());
String filename = "hello.java";
System.out.println(filename.endsWith(".java"));
System.out.println(filename.startsWith("hello"));
System.out.println(str.replace("java", "php"));
String say = "java is the best programing language";
String[] arr = say.split(" ");
System.out.println(arr.length);
for (String s : arr) {
System.out.println(s);
}
//equals()判断相等
//compareTo()比较大小
String s1 = "hello";
String s2 = "HELLO";
System.out.println(s1.equals(s2));
System.out.println(s1.equalsIgnoreCase(s2));//忽略大小写
String s3 = "abc";
String s4 = "xyz";
System.out.println(s3.compareTo(s4));//s3的位置减去s4的位置
String s5 = "abcxyz";
System.out.println(s3.compareTo(s5));//s3的长度减去s5的长度
}
}
可变字符串
-
StringBuffer:可变长字符串,jdk1.0提供,运行效率慢、线程安全。
-
StringBulider:可变长字符串,jdk1.5提供,运行效率快、线程不安全。(单线程优先使用这个)
- 效率比String高
- 比Stirng节省内存
package club.often.Demo04;
public class buffer {
public static void main(String[] args) {
//StringBuilder用法与之相同
StringBuffer sb = new StringBuffer();
//append() 追加
sb.append("java");
System.out.println(sb.toString());
sb.append("世界第一");
System.out.println(sb.toString());
//insert() 插入
sb.insert(0,"编程语言");
System.out.println(sb.toString());
//replace() 替换
sb.replace(4,8,"php");
System.out.println(sb.toString());
//delete() 删除
sb.delete(0, 4);
System.out.println(sb.toString());
sb.reverse();//翻转
sb.delete(0,sb.length());//清空
}
}
Arrays类
package club.aoba.www;
import java.util.Arrays;
public class Demo24 {
public static void main(String[] args) {
int [] a = {123,2,324,12,5,4,6,35,879,2423,64};
System.out.println(a);
//打印数组元素
System.out.println(Arrays.toString(a));
//排序:升序
Arrays.sort(a);
System.out.println(Arrays.toString(a));
//填充
Arrays.fill(a, 0);
System.out.println(Arrays.toString(a));
}
//重复造轮子
public static void printArr(int[] arrays)
{
for (int i = 0; i < arrays.length; i++) {
System.out.print(arrays[i]+", ");
}
}
}
BigDecimal类
-
很多实际应运用中需要精确运算,而double是近似值储存,不再符合要求,需要借助BigDecimal
-
Decimal:n. 小数;adj. 十进制的,小数的;
-
位置:java.math包中
-
作用:精确计算浮点数
-
创建方式:BigDecimal bd = new BigDecimal(“1.0”);
package club.often.Demo05;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Test {
public static void main(String[] args) {
//大的浮点数精确计算
BigDecimal bd1 = new BigDecimal("1.0");//传递字符串
BigDecimal bd2 = new BigDecimal("0.9");
BigDecimal r1 = bd1.subtract(bd2);//减法
System.out.println(r1);
BigDecimal r2 = bd1.add(bd2);//加法
System.out.println(r2);
BigDecimal r3 = bd1.multiply(bd2);//乘法
System.out.println(r3);
BigDecimal r4 = new BigDecimal("1.4").subtract(new BigDecimal("0.5")).divide(new BigDecimal("0.9"));
System.out.println(r4);
//除不尽会报异常,要指定保留位数和模式
BigDecimal r5 = new BigDecimal("10").divide(new BigDecimal("3"),2, RoundingMode.HALF_UP);//保留两位,四舍五入
System.out.println(r5);
}
}
Date类
-
Date类表示特定的瞬间,精确到毫秒。
-
Date类中的大部分方法已经被Calendar类中的方法所取代
-
有一些老的项目使用了这个类
package club.often.Demo06;
import java.util.Date;
public class date {
public static void main(String[] args) {
Date date1 = new Date();
System.out.println(date1.toString());
System.out.println(date1.toLocaleString());//过时
//getTime返回自1970年1月1日 00:00:00 GMT 以来 经过的毫秒数 该日期为Unix元年
Date date2 = new Date(date1.getTime() - 60 * 60 * 24 * 1000);
System.out.println(date2.toLocaleString());
System.out.println(date1.after(date2));
System.out.println(date1.before(date2));
System.out.println(date1.compareTo(date2));
System.out.println(date2.compareTo(date1));
System.out.println(date2.compareTo(date2));
System.out.println(date1.equals(date2));
}
}
Calendar类
- 提供了获取或设置各种日历字段的方法
- 构造方法由于修饰符是protected,所以无法直接创建该对象
package club.often.Demo06;
import java.util.Calendar;
public class Cal {
public static void main(String[] args) {
//创建calendar对象,使用静态方法
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getTime().toLocaleString());
System.out.println(calendar.getTimeInMillis());
//获取时间信息
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);//0~11
int day = calendar.get(Calendar.DAY_OF_MONTH);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
System.out.println(year+" "+(month+1)+" "+ day+" "+hour+" "+minute+" "+second);
//修改时间
Calendar calendar2 = Calendar.getInstance();
calendar2.set(Calendar.DAY_OF_MONTH,5);
System.out.println(calendar2.getTime().toLocaleString());
//add方法
calendar2.add(Calendar.HOUR,1);
System.out.println(calendar2.getTime().toLocaleString());
//获取最大最小值
System.out.println(calendar2.getActualMaximum(Calendar.DAY_OF_MONTH));//这个月有多少天
System.out.println(calendar2.getActualMinimum(Calendar.DAY_OF_MONTH));
}
}
SimpleDateFormat类
- SimpleDateFormat是一个以与语言环境有关的方式来格式化和解析日期的具体类
- 进行格式化(日期–>文本)、解析(文本–>日期)
- 常用的时间模式字母
字母 | 日期或时间 | 示例 |
---|---|---|
y | 年 | 2019 |
M | 年中月份 | 08 |
d | 月中天数 | 10 |
H | 一天中小时数(0~23) | 22 |
m | 分钟 | 16 |
s | 秒 | 59 |
S | 毫秒 | 367 |
package club.often.Demo06;
import java.text.SimpleDateFormat;
import java.util.Date;
public class SDF {
public static void main(String[] args) throws Exception{
//创建SimpleDateFormat对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日HH:mm:ss");
//创建Date
Date date = new Date();
//格式化date
String str = sdf.format(date);
System.out.println(str);
//解析
Date date2 = sdf.parse("1990年05月21日12:12:900");
System.out.println(date2);
}
}
System类
- 系统类,主要用于获取系统的属性数据和其他操作,构造方法私有
package club.often.Demo07;
public class Sys {
public static void main(String[] args) {
//arraycopy数组的复制
//原数组 从哪个位置开始复制 目标数组 目标数组的位置 复制的长度
int[] arr = {20,18,15,8,35,26,45,90};
int[] dest = new int[8];
System.arraycopy(arr,0,dest,0,arr.length);
for (int i : dest) {
System.out.println(i);
}
//计时
System.out.println(System.currentTimeMillis());
long start = System.currentTimeMillis();
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
long end = System.currentTimeMillis();
System.out.println("用时:"+(end-start));
//告诉垃圾回收器回收
System.gc();
//退出gvm 0正常退出 非0非正常退出
System.exit(0);
//后面代码就忽略执行了
System.out.println("aoba");
}
}
集合框架
什么是集合
- 概念:对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能
- 和数组的区别:数组长度固定,集合长度不固定;数组可以存储基本类型和引用类型,集合只能存储引用类型
- 位置:java.util.*;
Collection
体系
- Collection为该体系结构的根接口,代表一组对象,成为“集合”
- List接口的特点:有序、有下标、元素可重复
- Set接口的特点:无序、无下标、元素不能重复
Collection父接口
- 特点:代表一组任意类型的对象,无序、无下标、不能重复
- 方法:
- boolean add (Object obj) 添加一个对象
- boolean addAll(Collection c)将一个集合中的所有对象添加到此集合中
- void clear()清空集合中所有对象
- boolean contains(Object obj)检查集合中是否包含obj对象
- boolean equals(Object obj)比较此集合是否与指定对象相等
- boolean isEmpty()判断集合是否为空
- boolean remove(Object obj)移除obj对象
- int size()返回集合中元素的个数
- Object[] toArray()将此集合转换成数组
使用
例1
package club.collection.Demo01;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
//创建集合
Collection collection = new ArrayList();
//添加元素
collection.add("苹果");
collection.add("西瓜");
collection.add("榴莲");
System.out.println("元素个数:"+collection.size());
System.out.println(collection);
//遍历元素
//增强for
for (Object o : collection) {
System.out.println(o);
}
//迭代器
Iterator iterator = collection.iterator();
//hasNext()
//next()
//remove()
while(iterator.hasNext()){
System.out.println(iterator.next());
//迭代过程中不允许使用collection的删除方法
}
//判断
System.out.println(collection.contains("西瓜"));
System.out.println(collection.isEmpty());
//删除元素
collection.remove("榴莲");
System.out.println("元素个数:"+collection.size());
collection.clear();
System.out.println("元素个数:"+collection.size());
}
}
例2
package club.collection.Demo02;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package club.collection.Demo02;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
//新建一个collection对象
Collection collection = new ArrayList<>();
//添加数据
Student s1 = new Student("张三", 20);
Student s2 = new Student("张四", 18);
Student s3 = new Student("张五", 22);
collection.add(s1);
collection.add(s2);
collection.add(s3);
System.out.println(collection.size());
System.out.println(collection.toString());
//遍历
for (Object o : collection) {
System.out.println(o);
}
Iterator it = collection.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//判断
System.out.println(collection.contains(s1));
System.out.println(collection.isEmpty());
//删除
collection.remove(s1);
System.out.println("删除之后:"+collection.size());
collection.clear();
}
}
List集合
List子接口
- 特点:有序、有下标、元素可以重复
package club.collection.Demo03;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class MyList {
public static void main(String[] args) {
//创建集合对象
List list = new ArrayList<>();
//添加元素
list.add("苹果");
list.add("小米");
list.add(0,"华为");
System.out.println("元素个数:"+list.size());
System.out.println(list);
//遍历
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
for (Object o : list) {
System.out.println(o);
}
Iterator it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
//列表迭代器,允许按任一方向遍历列表,可以添加删除修改元素
ListIterator listIterator = list.listIterator();
while (listIterator.hasNext()){
System.out.println(listIterator.nextIndex());
System.out.println(listIterator.next());
}
while(listIterator.hasPrevious()){
System.out.println(listIterator.previousIndex());
System.out.println(listIterator.previous());
}
//判断
System.out.println(list.contains("苹果"));
System.out.println(list.isEmpty());
//获取
System.out.println(list.indexOf("华为"));
System.out.println(list.get(0));
//删除
list.remove("苹果");
list.remove(1);
System.out.println(list);
list.clear();
}
}
package club.collection.Demo03;
import java.util.ArrayList;
import java.util.List;
public class MyList2 {
public static void main(String[] args) {
//创建集合
List list = new ArrayList();
//添加数字数据(自动装箱)
list.add(20);
list.add(30);
list.add(40);
list.add(50);
list.add(60);
System.out.println("元素个数:"+list.size());
System.out.println(list);
//subList返回子集合,含头不含尾
List subList = list.subList(1,3);
System.out.println(subList);
//删除
//list.remove(0);//根据下标来删除
list.remove((Object) 20);
list.remove(new Integer(30));
list.remove(Integer.valueOf(40));
System.out.println(list);
}
}
List实现类
-
ArrayList【重点】数组列表
- 数组结构实现,查询快、增删慢
- jdk1.2版本,运行效率快、线程不安全
-
Vector:
- 数组结构实现,查询快、增删慢
- jdk1.0版本,运行效率慢、线程安全
-
LinkedList 链表
- 链表结构实现(双向链表),增删快、查询慢
ArrayList使用
package club.collection.Demo03;
import club.collection.Demo02.Student;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class MyList3 {
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
//添加元素
Student s1 = new Student("刘德华", 20);
Student s2 = new Student("郭富城", 22);
Student s3 = new Student("梁朝伟", 18);
arrayList.add(s1);
arrayList.add(s2);
arrayList.add(s3);
System.out.println("元素个数:"+arrayList.size());
System.out.println(arrayList);
//遍历
Iterator iterator = arrayList.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
ListIterator listIterator = arrayList.listIterator();
while (listIterator.hasNext()){
System.out.println(listIterator.next());
}
while (listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
//判断
System.out.println(arrayList.contains(s1));
//重写后改变了比较规则,比名字和年龄
System.out.println(arrayList.contains(new Student("郭富城",22)));
System.out.println(arrayList.isEmpty());
//查找
System.out.println(arrayList.indexOf(s1));
System.out.println(arrayList.indexOf(new Student("郭富城",22)));
//删除
arrayList.remove(s1);
//假设程序员认为只要名字,年龄相同,就是同一个人,需要重写equals方法
arrayList.remove(new Student("郭富城",22));
System.out.println("元素个数:"+arrayList.size());
System.out.println(arrayList);
}
}
package club.collection.Demo02;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(null == obj)
return false;
if(obj instanceof Student){
Student s = (Student) obj;
if(this.name.equals(s.getName())&&this.age==s.age)
return true;
}
return false;
}
}
ArrayList源码分析
默认容量大小为10
如果没有向集合中添加任何元素,容量为0
private static final int DEFAULT_CAPACITY = 10;
存放元素的数组
transient Object[] elementData;
实际的元素个数
private int size;
本质为动态数组
Vector使用
package club.collection.Demo03;
import java.util.Enumeration;
import java.util.Vector;
public class MyList4 {
public static void main(String[] args) {
//创建集合
Vector<Object> vector = new Vector<>();
//添加
vector.add("草莓");
vector.add("芒果");
vector.add("西瓜");
System.out.println("元素个数:"+vector.size());
System.out.println(vector);
//遍历:使用枚举器
Enumeration elements = vector.elements();
while (elements.hasMoreElements()){
System.out.println(elements.nextElement());
}
//判断
System.out.println(vector.contains("西瓜"));
System.out.println(vector.isEmpty());
//其他方法
System.out.println(vector.firstElement());
System.out.println(vector.lastElement());
System.out.println(vector.get(0));
System.out.println(vector.elementAt(0));
//删除
vector.remove(0);
vector.remove("西瓜");
vector.clear();
}
}
LinkedList使用
package club.collection.Demo03;
import club.collection.Demo02.Student;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
public class MyList5 {
public static void main(String[] args) {
//创建集合
LinkedList<Object> linkedList = new LinkedList<>();
//添加
Student s1 = new Student("刘德华", 20);
Student s2 = new Student("郭富城", 22);
Student s3 = new Student("梁朝伟", 18);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
System.out.println("元素个数:"+linkedList.size());
System.out.println(linkedList);
//遍历
for (int i = 0; i < linkedList.size(); i++) {
System.out.println(linkedList.get(i));
}
for (Object o : linkedList) {
System.out.println(o);
}
Iterator iterator = linkedList.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
ListIterator listIterator = linkedList.listIterator();
while (listIterator.hasNext()){
System.out.println(listIterator.next());
}
//判断
System.out.println(linkedList.contains(s1));
System.out.println(linkedList.isEmpty());
//获取
System.out.println(linkedList.indexOf(s1));
//删除
linkedList.remove(s1);
System.out.println("删除之后:"+linkedList.size());
}
}
LinkedList源码分析
-
双向链表
-
size
-
头节点
-
尾节点
-
节点:元素、下一个节点、前一个节点
ArrayList和LinkedList的区别
- 不同结构实现方式
泛型
概述
- Java泛型是jdk1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
- 常见形式有泛型类、泛型接口、泛型方法
- 语法:<T,…> T称为类型占位符,表示一种引用类型
- 好处:提高代码的重用性,防止类型转换异常,提高代码的安全性
泛型类
package club.MyGeneric.Demo01;
//泛型类:类名<T>
//T是类型占位符,表示一种引用类型,可以写多个使用逗号隔开
public class MyG<T> {
//使用泛型
//创建变量
T t;
//不能使用new T t = new T(); 没法保证传过来的类型构造方法一定能用
//作为方法的参数
public void show(T t){
System.out.println(t);
}
//泛型作为方法的返回值
public T getT(){
return t;
}
}
package club.MyGeneric.Demo01;
public class Test {
public static void main(String[] args) {
//使用泛型类创建对象
MyG<String> myG = new MyG<String>();//后面尖括号可以不写
myG.t = "hello";
myG.show("world");
String str = myG.getT();
MyG<Integer> myG1 = new MyG<>();
myG1.t = 100;
myG1.show(200);
Integer integer = myG1.getT();
//注意:
//泛型只能使用引用类型
//不同泛型类型对象之间不能相互赋值
}
}
泛型接口
package club.MyGeneric.Demo02;
//泛型接口:接口名<T>
public interface MyInterface<T> {
String name = "张三";
//不能使用泛型来创建静态常量
T server(T t);
}
package club.MyGeneric.Demo02;
public class MyInterfaceImpl implements MyInterface<String>{
@Override
public String server(String s) {
System.out.println(s);
return s;
}
}
package club.MyGeneric.Demo02;
public class MyInterfaceImpl2<T> implements MyInterface<T>{
@Override
public T server(T t) {
System.out.println(t);
return t;
}
}
package club.MyGeneric.Demo02;
public class Test {
public static void main(String[] args) {
MyInterfaceImpl impl = new MyInterfaceImpl();
impl.server("aoba");
MyInterfaceImpl2<Integer> impl2 = new MyInterfaceImpl2<>();
impl2.server(1000);
}
}
泛型方法
package club.MyGeneric.Demo03;
public class Method {
//泛型方法:<T>方法返回值
public <T> T show(T t){
System.out.println("泛型方法"+ t);
return t;
}
}
package club.MyGeneric.Demo03;
public class Test {
public static void main(String[] args) {
Method method = new Method();
method.show("aoba");
method.show(200);
method.show(3.14);
//类型不需要传递,类型由传递的数据决定
}
}
泛型集合
- 概念:参数化类型、类型安全的集合,强制集合元素的类型必须一致
- 特点
- 编译时即可检查,而非运行时抛出异常
- 访问时不必类型转换(拆箱)
- 不同泛型之间引用不能相互赋值,泛型不存在多态
package club.MyGeneric.Demo04;
import club.collection.Demo02.Student;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
public class Test {
public static void main(String[] args) {
ArrayList<Object> arrayList = new ArrayList<>();
arrayList.add("xxx");
arrayList.add("yyy");
arrayList.add(10);
arrayList.add(20);
for (Object o : arrayList) {
System.out.println(o);
}
ArrayList<String> arrayList2 = new ArrayList<>();
arrayList2.add("xxx");
arrayList2.add("yyy");
//arrayList2.add(10);
//arrayList2.add(20);只能添加String类型
LinkedList<Student> linkedList = new LinkedList<>();
//只能添加Student类型
Student s1 = new Student("刘德华", 20);
Student s2 = new Student("郭富城", 22);
Student s3 = new Student("梁朝伟", 18);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
ListIterator<Student> it = linkedList.listIterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
Set集合
Set子接口
- 特点:无序、无下标、元素不可重复
- 方法:全部继承自Collection中的方法
Set接口使用
package club.MySet.Demo01;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Test {
public static void main(String[] args) {
//创建集合
//特点:无序、没有下标、不能重复
Set<String> set = new HashSet<>();
//添加
set.add("小米");
set.add("苹果");
set.add("华为");
set.add("华为");//没有添加进来
System.out.println("数据个数:"+set.size());
System.out.println(set);
//遍历
//增强for
for (String s : set) {
System.out.println(s);
}
//迭代器
Iterator<String> iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(set.contains("华为"));
System.out.println(set.isEmpty());
//删除
set.remove("小米");
System.out.println(set);
set.clear();
}
}
Set实现类
-
HashSet:
- 基于HashCode计算元素存放位置
- 当存入元素的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入
-
TreeSet
- 红黑树
- 基于排列顺序实现元素不重复
- 实现了SortedSet接口,对集合元素自动排序
- 元素对象的类型必须实现Comparable接口,指定排序规则
- 通过CompareTo方法确定是否为重复元素
HashSet使用
package club.MySet.Demo02;
import java.util.HashSet;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
//存储结构:哈希表(数组+链表+红黑树)
HashSet<String> hashSet = new HashSet<>();
//添加
hashSet.add("b");
hashSet.add("a");
hashSet.add("d");
hashSet.add("c");
System.out.println("元素个数:"+hashSet.size());
System.out.println(hashSet);
//遍历
for (String s : hashSet) {
System.out.println(s);
}
Iterator<String> iterator = hashSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(hashSet.contains("d"));
System.out.println(hashSet.isEmpty());
//删除
hashSet.remove("c");
System.out.println(hashSet);
}
}
package club.MySet.Demo03;
import java.util.Objects;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
//alt + insert自动重写
}
package club.MySet.Demo03;
import java.util.HashSet;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
//创建集合
HashSet<Person> people = new HashSet<>();
//添加数据
Person s1 = new Person("桃", 16);
Person s2 = new Person("夏美子", 16);
Person s3 = new Person("蜜柑", 16);
people.add(s1);
people.add(s2);
people.add(s3);
people.add(new Person("桃",16));//默认能够添加进来
//假设名字年龄相同则认为相同,可以重写hashCode()方法和equals()方法,那么就添加不进来
//存储的过程(重复依据):
//根据hashcode计算保存的位置,如果此位置为空则直接保存
//不为空:再执行equals方法,如果为true,则认为重复,否则形成链表
System.out.println("元素个数:"+people.size());
System.out.println(people.toString());
//遍历
for (Person person : people) {
System.out.println(person);
}
Iterator<Person> iterator = people.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(people.contains(s1));
System.out.println(people.contains(new Person("桃",16)));//重写后为true
System.out.println(people.isEmpty());
//删除
people.remove(s2);
people.remove(new Person("桃",16));//重写完后能够删掉
System.out.println(people);
}
}
- hashCode源码
- 结果乘31的原因:
- 31是一个质数,减少散列冲突,让计算出的结果尽量不一样,数据放在不同的位置
- 31提高执行效率,将乘法运算换成位运算: 31*i = (i<<5)-i;
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
TreeSet使用
package club.MySet.Demo04;
import java.util.Iterator;
import java.util.TreeSet;
public class Test {
public static void main(String[] args) {
//创建集合
TreeSet<String> treeSet = new TreeSet<>();
//添加元素
treeSet.add("xyz");
treeSet.add("abc");
treeSet.add("hello");
treeSet.add("xyz");//没有添加进来
System.out.println("元素个数:"+treeSet.size());
System.out.println(treeSet);
//遍历
for (String s : treeSet) {
System.out.println(s);
}
Iterator<String> iterator = treeSet.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(treeSet.contains("abc"));
System.out.println(treeSet.isEmpty());
//删除
treeSet.remove("xyz");
System.out.println(treeSet);
}
}
package club.MySet.Demo03;
import java.util.Objects;
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age && Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
//alt + insert自动重写
//先按照姓名比,再按年龄比
@Override
public int compareTo(Person o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.age - o.getAge();
return n1==0?n2:n1;
}
}
package club.MySet.Demo05;
import club.MySet.Demo03.Person;
import java.util.Iterator;
import java.util.TreeSet;
public class Test {
public static void main(String[] args) {
//创建集合
TreeSet<Person> treeSet = new TreeSet<>();
//添加元素
Person s1 = new Person("桃", 16);
Person s2 = new Person("夏美子", 16);
Person s3 = new Person("蜜柑", 16);
//元素必须要实现Comparable接口
//compareTo的返回值为0认为重复
treeSet.add(s1);
treeSet.add(s2);
treeSet.add(s3);
System.out.println("元素个数:"+treeSet.size());
System.out.println(treeSet);
//遍历
for (Person person : treeSet) {
System.out.println(person);
}
Iterator<Person> iterator = treeSet.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
//判断
System.out.println(treeSet.contains(s1));
System.out.println(treeSet.contains(new Person("蜜柑", 16)));
System.out.println(treeSet.isEmpty());
//删除
treeSet.remove(s1);
System.out.println(treeSet);
}
}
Comparator接口
- 实现定制比较(比较器)
package club.MySet.Demo06;
import club.MySet.Demo03.Person;
import java.util.Comparator;
import java.util.TreeSet;
public class Test {
public static void main(String[] args) {
//创建集合并指定比较规则
TreeSet<Person> people = new TreeSet<>(new Comparator<Person>(){
//先比年龄,再比姓名
@Override
public int compare(Person o1, Person o2) {
int n1 = o1.getAge()-o2.getAge();
int n2 = o1.getName().compareTo(o2.getName());
return n1==0?n2:n1;
}
});
//添加元素
Person s1 = new Person("桃", 17);
Person s2 = new Person("夏美子", 16);
Person s3 = new Person("蜜柑", 18);
people.add(s1);
people.add(s2);
people.add(s3);
System.out.println(people);
}
}
Map体系集合
概述
- 特点:用于储存任意键值对(Key—Value)
- 键:无序、无下标、不允许重复
- 值:无序、无下标、允许重复
Map接口的使用
package club.MyMap.Demo01;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
//创建map集合
Map<String, String> map = new HashMap<>();
//添加元素
map.put("cn","中国");
map.put("uk","英国");
map.put("usa","美国");
System.out.println("元素个数:"+map.size());
System.out.println(map);
//遍历
//使用KeySet()
Set<String> keySet = map.keySet();
for (String s : keySet) {
System.out.println(s+" : "+map.get(s));
}
//使用entrySet()效率高于keySet()
//Map.Entry<>内部接口 一个entry就是一个映射对/键值对
Set<Map.Entry<String, String>> entrySet = map.entrySet();
for (Map.Entry<String, String> stringStringEntry : entrySet) {
System.out.println(stringStringEntry.getKey()+" : "+stringStringEntry.getValue());
}
//判断
System.out.println(map.containsKey("cn"));
System.out.println(map.containsValue("泰国"));
System.out.println(map.isEmpty());
//删除
map.remove("usa");
System.out.println(map);
}
}
HashMap使用
- jdk1.2版本,线程不安全,运行效率快;允许使用null作为key或是value
- 默认初始容量:16
- 默认加载因子:0.75
- 存储结构:哈希表(数组+链表+红黑树)
package club.MyMap.Demo02;
import java.util.Objects;
public class Student {
private String name;
private int stuNO;
public Student() {
}
public Student(String name, int stuNO) {
this.name = name;
this.stuNO = stuNO;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStuNO() {
return stuNO;
}
public void setStuNO(int stuNO) {
this.stuNO = stuNO;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", stuNO=" + stuNO +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return stuNO == student.stuNO && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, stuNO);
}
}
package club.MyMap.Demo02;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Test {
public static void main(String[] args) {
//创建集合
HashMap<Student, String> students = new HashMap<>();
//添加元素
Student s1 = new Student("孙悟空", 100);
Student s2 = new Student("猪八戒", 101);
Student s3 = new Student("沙和尚", 102);
students.put(s1,"北京");
students.put(s2,"上海");
students.put(s3,"太原");
students.put(new Student("沙和尚",102),"太原");//默认能添加进来
//使用key的hashcode和equals作为重复依据
//重写后就添加不进来了
System.out.println(students.size());
System.out.println(students);
//遍历
Set<Student> keySet = students.keySet();
for (Student student : keySet) {
System.out.println(student+" : "+students.get(student));
}
Set<Map.Entry<Student, String>> entrySet = students.entrySet();
for (Map.Entry<Student, String> entry : entrySet) {
System.out.println(entry.getKey()+" : "+entry.getValue());
}
//判断
System.out.println(students.containsKey(s1));
//重写后返回true
System.out.println(students.containsKey(new Student("沙和尚", 102)));
System.out.println(students.containsValue("太原"));
//删除
students.remove(s1);
System.out.println(students);
}
}
HashTable
- jdk1.0版本,线程安全,运行效率慢,不允许null作为key或是value
- 不常用
- 子类:Properties,要求key和value都是String。通常用于配置文件的读取。
TreeMap使用
- 实现了SortedMap接口(Map子接口),可以对key自动排序
package club.MyMap.Demo02;
import java.util.Objects;
public class Student implements Comparable<Student>{
private String name;
private int stuNO;
public Student() {
}
public Student(String name, int stuNO) {
this.name = name;
this.stuNO = stuNO;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStuNO() {
return stuNO;
}
public void setStuNO(int stuNO) {
this.stuNO = stuNO;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", stuNO=" + stuNO +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return stuNO == student.stuNO && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, stuNO);
}
//比学号
@Override
public int compareTo(Student o) {
int n1 = this.stuNO - o.getStuNO();
return n1;
}
}
package club.MyMap.Demo03;
import club.MyMap.Demo02.Student;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class Test {
public static void main(String[] args) {
//创建集合
TreeMap<Student, String> treeMap = new TreeMap<>();
//添加
Student s1 = new Student("孙悟空", 100);
Student s2 = new Student("猪八戒", 101);
Student s3 = new Student("沙和尚", 102);
treeMap.put(s1,"小店");
treeMap.put(s2,"迎泽");
treeMap.put(s3,"草坪");
System.out.println(treeMap.size());
System.out.println(treeMap);
//遍历
Set<Student> keySet = treeMap.keySet();
for (Student student : keySet) {
System.out.println(student+" : "+treeMap.get(student));
}
for (Map.Entry<Student, String> entry : treeMap.entrySet()) {
System.out.println(entry.getKey()+" : "+entry.getValue());
}
//判断
System.out.println(treeMap.containsKey(s1));
System.out.println(treeMap.containsValue("晋源"));
//删除
treeMap.remove(s3);
System.out.println(treeMap);
}
}
- 与TreeSet关系:TreeSet用TreeMap的key来保存数据
Collections工具类
- 概念:集合工具类,定义了除了存取以外的集合常用方法
package club.collection.Demo04;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Test {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(20);
list.add(5);
list.add(12);
list.add(30);
list.add(6);
//sort排序
System.out.println(list);
Collections.sort(list);
System.out.println(list);
//binarySearch二分查找
int search = Collections.binarySearch(list, 12);
int search2 = Collections.binarySearch(list, 13);
System.out.println(search);
System.out.println(search2);
//copy复制,要求两个集合大小相同
ArrayList<Integer> dest = new ArrayList<>();
for (int i = 0; i < 5; i++) {
dest.add(0);
}
Collections.copy(dest, list);
System.out.println(dest);
//reverse翻转
Collections.reverse(list);
System.out.println(list);
//shuffle打乱
Collections.shuffle(list);
System.out.println(list);
//list转成数组
Integer[] array = list.toArray(new Integer[0]);
System.out.println(array.length);
System.out.println(Arrays.toString(array));
//数组转成list
String[] names = {"张三","李四","王五"};
List<String> list1 = Arrays.asList(names);
//该集合是一个受限集合:不能添加和删除
System.out.println(list1);
//基本类型数组转成集合时,需要修改为包装类
Integer[] nums = {100,200,300,400,500};
List<Integer> list2 = Arrays.asList(nums);
System.out.println(list2);
}
}
简单介绍下剩下的知识
高级
- IO
- 多线程/ JUC并发编程
- 网络编程
- 注解和反射
- JVM
JavaWeb
开源框架
rintln(students.containsValue(“太原”));
//删除
students.remove(s1);
System.out.println(students);
}
}
> HashTable
- jdk1.0版本,线程安全,运行效率慢,不允许null作为key或是value
- 不常用
- 子类:Properties,要求key和value都是String。通常用于配置文件的读取。
> TreeMap使用
- 实现了SortedMap接口(Map子接口),可以对key自动排序
```java
package club.MyMap.Demo02;
import java.util.Objects;
public class Student implements Comparable<Student>{
private String name;
private int stuNO;
public Student() {
}
public Student(String name, int stuNO) {
this.name = name;
this.stuNO = stuNO;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getStuNO() {
return stuNO;
}
public void setStuNO(int stuNO) {
this.stuNO = stuNO;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", stuNO=" + stuNO +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return stuNO == student.stuNO && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, stuNO);
}
//比学号
@Override
public int compareTo(Student o) {
int n1 = this.stuNO - o.getStuNO();
return n1;
}
}
package club.MyMap.Demo03;
import club.MyMap.Demo02.Student;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class Test {
public static void main(String[] args) {
//创建集合
TreeMap<Student, String> treeMap = new TreeMap<>();
//添加
Student s1 = new Student("孙悟空", 100);
Student s2 = new Student("猪八戒", 101);
Student s3 = new Student("沙和尚", 102);
treeMap.put(s1,"小店");
treeMap.put(s2,"迎泽");
treeMap.put(s3,"草坪");
System.out.println(treeMap.size());
System.out.println(treeMap);
//遍历
Set<Student> keySet = treeMap.keySet();
for (Student student : keySet) {
System.out.println(student+" : "+treeMap.get(student));
}
for (Map.Entry<Student, String> entry : treeMap.entrySet()) {
System.out.println(entry.getKey()+" : "+entry.getValue());
}
//判断
System.out.println(treeMap.containsKey(s1));
System.out.println(treeMap.containsValue("晋源"));
//删除
treeMap.remove(s3);
System.out.println(treeMap);
}
}
- 与TreeSet关系:TreeSet用TreeMap的key来保存数据
Collections工具类
- 概念:集合工具类,定义了除了存取以外的集合常用方法
package club.collection.Demo04;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Test {
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<>();
list.add(20);
list.add(5);
list.add(12);
list.add(30);
list.add(6);
//sort排序
System.out.println(list);
Collections.sort(list);
System.out.println(list);
//binarySearch二分查找
int search = Collections.binarySearch(list, 12);
int search2 = Collections.binarySearch(list, 13);
System.out.println(search);
System.out.println(search2);
//copy复制,要求两个集合大小相同
ArrayList<Integer> dest = new ArrayList<>();
for (int i = 0; i < 5; i++) {
dest.add(0);
}
Collections.copy(dest, list);
System.out.println(dest);
//reverse翻转
Collections.reverse(list);
System.out.println(list);
//shuffle打乱
Collections.shuffle(list);
System.out.println(list);
//list转成数组
Integer[] array = list.toArray(new Integer[0]);
System.out.println(array.length);
System.out.println(Arrays.toString(array));
//数组转成list
String[] names = {"张三","李四","王五"};
List<String> list1 = Arrays.asList(names);
//该集合是一个受限集合:不能添加和删除
System.out.println(list1);
//基本类型数组转成集合时,需要修改为包装类
Integer[] nums = {100,200,300,400,500};
List<Integer> list2 = Arrays.asList(nums);
System.out.println(list2);
}
}
简单介绍下剩下的知识
高级
- IO
- 多线程/ JUC并发编程
- 网络编程
- 注解和反射
- JVM
JavaWeb
开源框架