java学习之旅
[TOC]
本篇文章更新java系列知识—持续更新中
快捷键速查
ctrl + shift + u 大小写替换
ctrl + alt +t 快速写一些方法,如try catch
alt + insert
sout 输出
psvm 主函数
day1 java初识
第一个HelloWord程序
/*
这里HelloWord是类名
void main 是方法,也是程序的入口
void 空
main 主函数
*/
class HelloWord{
public static void main(String[] args){
System.out.println("Hello Word!");
}
}
首先用 javac helloword.java –>编译为 helloword.class
然后 java helloword 执行(这里注意不要加后缀!)
结果如下:
注意点:
1、java中严格区分大小写
2、要记得更改编辑器的编码方式 要保持编码一致才能运行
3、每一行语句结束必须以;结束
4、注意缩进
5、类名是什么,生成的字节码文件是什么,与原文件名字没有直接关系。
6、当类是公共的,既用public修饰类,类名必须与文件名保持一致
7、一个java文件中可以有多个类,每个类在编译后都会生成一个字节码文件。
标识符
关键字有:
其中const和goto是保留字
规范:
1、见名知意
2、驼峰命名
当变量名 方法名 参数名 由两个或两个单词以上组成时,从第二个单词开始首字母大写
如:userName passWord
3、对常量进行命名时,每个单词的字母都大写,而且单词与单词之间使用_相连
如: MAX_NUM
4、对类进行命名时,对每一个单词的首字母大写
数据类型
基本数据类型(四类八种):
整数型:
byte 字节类型 short int long
浮点类型:
float 单精度 double 双精度
字符型:
char
布尔型:
boolean:
true false
引用类型数据:字符串 类 接口
常量
字符串常量 浮点类型常量 字符常量 布尔类型常量 内置的常量
“HelloWoerd” 3.14 ‘你’ true Math.PI
变量
在程序执行过程中,其值可以改变的量
三要素:
变量类型 变量名 变量值
如何申明变量?
数据类型+变量名
申明整数类型变量:
byte b; long 1;
同理可生成
float f; double d; char c; String s;
在方法内的变量 申明后要赋值才能使用
变量的实质就是申请内存
day2 java基础语法
进制转换:
class Sakura{
public static void main(String [] args){
System.out.println(666); //十进制
System.out.println(0b1010011010); //二进制 0b开头
System.out.println(01232); //八进制 0开头
System.out.println(0x29a); //十六进制 0x开头
}
}
输出结果:
计算机存储单位
1 byte = 8 bit; 没有符号的范围: 2^8-1 有符号(第一位做符号位): -128 - 127
整数类型 注意:
1、整数类型,默认的数据类型是int
2、错误:不兼容的类型:从int转换到byte可能有损失
当我们赋的值在byte或者short的范围内则不会有变化
但是当赋的值不在byte或者short的范围内则会将此值作为int类型处理
3、错误:过大的整数:2222222222
生命long类型数值的时候,要在数值的末尾+L
浮点类型 注意:
1、浮点类型 默认的数据类型是double
2、不兼容的类型:从double转换到float可能会有损失
申明float类型的数据 要在数值的末尾 + F
float f =3.14F
3、浮点类型底层采用的是科学计数法方式
4、小数底层存储方式与整数不同 有符号位 指数位 整数位
5、小数不能精确的表示一个值 (如果要精确的表示需要用到bigdecimal)
计算机如何存储数据
自动类型提升
基本类型数据转换:
1、自动类型提升
小的数据类型 可以自动转换为大的数据类型
int d = 3;
double f = d;
2、强制类型转换
错误:不兼容的类型,从double转换到int可能会有损失
强制转换的公式:
小的数据类型 标识符 = (小的数据类型)大的数据类型
double d = 3.14;
int num = (int)d;
特殊情况
class Sakura{
public static void main(String [] args){
int a = 200;
byte b = (byte)a;
System.out.println(b);
}
}
为什么这里是-56呢?
首先我们知道 int是四个字节,而byte只有一个字节,200的二进制数为 11001000
刚好byte可以全部接受,但是byte第一位是符号位,首位是1,所以是负数,计算机的存储方式是以补码的形式存储。11001000—>10110111(反码)—>10111000(补码)
转化为十进制就是-56
运算符
注意:
1、整数相除,不保留小数
2、如果想要显示小数,使用浮点类型计算
3、 byte与byte short与short char与char 做运算,或者他们之间混合运算,则结果会变为int类型
使用赋值运算符是不会发生类型转换的
逻辑运算符
运算符优先级
day3 流程控制语句
输入语句 scanner
import java.util.*;
class InputTest{
public static void main(String [] args){
Scanner input = new Scanner(System.in);
// 创建input对象, "input"是变量,可为任意值
// System.in 输入流
// 输入数据必须与接受类型匹配,不然会报错 如下图
//Scanner类型没有提供返回char类型数据的方法
/*
可以采用 字符串.charAt(0); 0代表字符串内第一个字符,1代表第二个......
char cc = "你好".charAt(0);
System.out.println(cc); ---你
*/
System.out.println("请输入你的年龄");
int age = input.nextInt();
System.out.println("你的年龄是"+age);
System.out.println("请输入你的身高");
double height = input.nextDouble();
System.out.println("你的身高是"+height);
System.out.println("请输入你的姓名");
String name = input.next();
System.out.println("你的姓名是"+name);
}
}
next与nextLine
键盘输入一个地址
/*
1、导包
2、创建对象
3、对象调方法
*/
import java.util.*;
class InputTest{
public static void main(String [] args){
Scanner input = new Scanner(System.in);
System.out.println("您的地址是");
String address = input.next();
System.out.println("您的地址是"+address);
}
}
注意:
next()无法接受 空格之后的内容
此时我们可以用nextLine(可以接受整行内容)
String address = input.nextLine();
nextLine存在一些问题:
import java.util.*;
class InputTest{
public static void main(String [] args){
Scanner input = new Scanner(System.in);
System.out.println("您的身高是");
double height = input.nextDouble();
System.out.println("您的身高是:"+height);
System.out.println("您的地址是");
String address = input.nextLine();
System.out.println("您的地址是:"+address);
}
}
当代码如上时,运行程序会出现以下后果:
我们发现第二个输出直接结束了,这是因为nextLine遇到回车,会误认为代码已经结束了。
解决办法:
在中间加入一个
input.nextLine();
来接受回车
这样问题就解决了
if单分支
/*
if分支:
if单分支
if(boolean表达式){
分支内容
}
*/
import java.util.*;
class IfTest{
public static void main(String [] args){
Scanner in = new Scanner(System.in);
System.out.println("请输入您的年龄");
int age = in.nextInt();
if(age >= 18){
System.out.println("您已经成年,可以上网了");
}
if(age < 18){
System.out.println("您还没有成年,please go out!");
}
}
}
小习题-闰年的标准
闰年的标准(两者满足其一即可):
1、能被4整除,不能被100整除
2、能被400整除
代码功能:
输入一个数判断是否是闰年
import java.util.*;
class RunYears{
public static void main(String [] args){
Scanner input = new Scanner(System.in);
System.out.println("请输入一个年份:");
int years = input.nextInt();
if((years%4==0&&years%100!=0)||(years%400==0))
System.out.println(years+"是闰年!");
}
}
if双分支
求三个数中的最大值
import java.util.*;
class MaxNum{
public static void main(String [] args){
int a = 50;
int b = 999;
int c = 12;
if(a > b){
if(a > c){
System.out.println("a是三个数中的最大值");
}else{
System.out.println("c是三个数中的最大值");
}
}else{
if(b < c){
System.out.println("c是三个数中的最大值");
}else{
System.out.println("b是三个数中的最大值");
}
}
}
}
if多分支
switch
case后面的数据必须与表达式类型一致
循环
满足特定条件反复执行的代码
任何一个标准的循环都有四个条件:
初始化条件
循环条件
循环体
迭代条件
实例:
import java.util.*;
class Repeat{
public static void main(String [] args){
int i = 0;
while(i<10){
System.out.println("Hello Word");
i++;
}
}
}
day4 循环
do while
随机数公式
Math.random(); 返回一个double值 [0.0,1.0]
如果我们要求 m~n的数
公式: (int)(Math.random()*(n-m+1)+m);
for循环
for 循环:
for(初始化条件;循环条件;迭代条件){
循环体
}
break
continue、return、continue的区别
day5 数组
数组初识
数组: 容器 存储数据
相同类型数据的有序集合
声明一个数组
数组初始化
两种
静态初始化
arr = new int[]{1,2,3,4,5};
int [] arr1 = new int[]{1,2,3,4,5};//已经指定元素
动态初始化
arr =new int[4]; //没有指定元素
double [] arrDouble = new double[5];
注意:
数组内元素的类型要保持一致
数组元素的访问
int [] arr = {1,2,3};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2 ]);
数组长度显示
arr.length 表示数组内元素的数量
System.out.println(arr.length);
获取最后一个元素的巧妙方法
System.out.println(arr[arr.length-1]);
数组的默认初始化
数组声明之后,数据类型不同,数组中就会有不同的默认值
byte 0 short 0 int 0 long 0 double 0.0 float 0.0 char ‘\u0000’ boolean false
引用数据类型默认值都是null String
数组的遍历
1、借用for循环
for(int i = 0;i<(arr.length-1);i++){
System.out.println(arr[i]);
}
2、
代码:
import java.util.*;
class ArrayTest{
public static void main(String [] args){
int [] arr = {1,2,3,4,5,6,7,8,9};
for(int i = 0;i<(arr.length-1);i++){
System.out.println(arr[i]);
}
System.out.println("----------------------");
for(int a :arr){
System.out.println(a);
}
}
}
数组的内存划分
数组名
数组练习
学生成绩
import java.util.*;
class ArrayTest{
public static void main(String [] args){
int [] arr = new int[5];
Scanner input =new Scanner(System.in);
int scores = 0;
for(int i = 0;i < 5;i++){
System.out.println("请输入第"+(i+1)+"个学生的成绩");
arr[i] = input.nextInt();
scores = scores+arr[i];
}
float ave = scores/5;
System.out.println("学生的总成绩是:"+scores);
System.out.println("学生的平均成绩为:"+ave);
for(int i = 0;i < 5;i++){
System.out.println("第"+(i+1)+"个学生的成绩是"+arr[i]);
}
}
}
数组找最值
import java.util.*;
class ArrayTest{
public static void main(String [] args){
int [] arr = {85,958,235,41,-85,69,74,666,854,9644};
int one = arr[0];
for(int i = 1;i < 10;i++){
if(one < arr[i]){
one = arr[i];
}else{
continue;
}
}
System.out.println("找到了最大的钻石,它的克拉是"+one);
}
}
冒泡排序
import java.util.*;
class MaoPao{
public static void main(String [] args){
int [] arr = {85,958,235,41,-85,69,74,666,854,9644,856,884};
for(int ele :arr){
System.out.print(ele+" ");
}
System.out.print("-->");
int tmp = 0;
for(int j = 0;j< (arr.length-1);j++){
for(int i = 0;i < (arr.length-1);i++ ){
if(arr[i] > arr[i+1]){
tmp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = tmp;
}else{
continue;
}
}
}
for(int ele :arr){
System.out.print(ele+" ");
}
}
}
优化:
1、专注于处理无序部分
for(int j = 0;j< (arr.length-1-i);j++){
2、解决无效排序
import java.util.*;
class MaoPao{
public static void main(String [] args){
int [] arr = {85,958,235,41,-85,69,74,666,854,9644,856,884};
for(int ele :arr){
System.out.print(ele+" ");
}
System.out.print("-->");
int tmp = 0;
for(int j = 0;j< (arr.length-1);j++){
boolean flag = true;
for(int i = 0;i < (arr.length-1);i++ ){
if(arr[i] > arr[i+1]){
tmp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = tmp;
flag = false;
}else{
continue;
}
}
if(flag == true)
break;
}
for(int ele :arr){
System.out.print(ele+" ");
}
}
}
day6 数组
查找指定元素的下标
import java.util.*;
class MaoPao{
public static void main(String [] args){
Scanner input = new Scanner(System.in);
System.out.println("请输入您要查找的元素:");
int a = input.nextInt();
int [] arr = {85,958,235,41,-85,69,74,666,854,9644,856,884};
int index = 0;
for(int i = 0;i<arr.length;i++){
if(a == arr[i]){
index = i;
break;
}else if(i == (arr.length-1)){
System.out.println("查无此数");
}
}
System.out.println("该元素的下标为"+index);
}
}
二维数组的声明
二维数组:存储一维数组的数组
int [][] arr; //推荐
int arr[][];
二维数组的静态初始化
int [][] arr = {{一维数组元素},{一维数组元素},{一维数组元素}}; //方式一
double [][] doubleArr = new double[][]{{一维数组元素},{一维数组元素},{一维数组元素}};
//方式二
二维数组的动态初始化
int [][] arr = new int[5][5];
这种一维数组可以不等长
double [][] doubleArr = new double[3][];
doubleArr[0] = new double[](3.14,6.28);
二维数组的遍历
普通for循环
增强for循环
二维数组内存图
二维数组练习
1
22
333
4444
55555
idea的使用
ctrl z 撤销
ctrl y 取消撤销
idea自带快捷键
以下写出来后+TAB
psvm 写一个main方法
public static void main(String[] args) {
}
sout 快速输出语句
System.out.println();
shift + enter 快速跳到下一行
CTRL D 快速删除
CTRL ALT 下 快速复制
ALT 上/下 快速移动代码
CTRL SHIFT F 格式化代码
CTRL / 快速单行注释
CTRL shift / 快速多行注释
day7 面向对象
面向对象思想概述
类和对象
创建类和对象
类的创建
[权限修饰符] class 类名{
}
对象的创建
new 类名();
创建对象内存图
包名相关
包名一般采用公司网址的倒序
com.guigu.项目名
com.guigu.shopping.login
java.lang不需要导包
java.sql 数据库相关
java.io IO流相关
java.net 网络编程相关
java.util 一些核心的工具类
ALT+ENTER 可以自动导包
示例变量内存图
栈:存放局部变量 执行方法也会开辟空间 (存储时先进后出)
本地方法栈: 当执行native方法、c/c++ 存放局部变量、执行方法也会开辟空间
方法区: 类的信息、变量信息、方法信息、常量信息 …
堆:用来存放 对象数组等等 new出来的东西
程序计数器:用于存储下一条指令
类变量(静态变量)
成员变量练习
声明一个圆的图形类
银行账号
两个类
成员变量练习内存图
方法的初识
形参和实参
返回值
实例方法
day8面向对象
基本类型值传递
引用数据类型传递
数组内存图
局部变量
定义到方法中的变量是局部变量,局部变量只在方法中有效
局部变量在使用前必须完成初始化,否则报错
定义到类中的变量是成员变量,成员变量只在类中有效
局部变量在方法调用后,才会进行初始化,当方法执行完毕就会随方法弹栈消失
可变形参
参数的个数可以是任意个 0~n
如何声明?
public static void sum(int...a){} //三个点
可变形参采用数组存储实参
xxxxxxxxxx public static void sum(double a , int...a){}
不能存在两个可变参数,且可变参数必须在最后
方法重载
不同的方法可以使用相同的方法名
要求:同一类中,同一方法名,不同的形参列表:数量、顺序、类型
方法调用时会根据不同的数据类型找到最佳匹配的方法
命令行参数
idea
命令行
class Sakura{
public static void main(String [] args){
for(String ele:args){
System.out.println(ele);
}
}
}
静态导入
导入一个类中的所有静态资源
递归
对象类型数组
封装的概念及四个权限修饰符的概念
属性的简单封装
day9面向对象
构造器
可以快速给成员变量赋值
创建类
构造
每一个类都会有一个无参构造器,但是当声明有参构造器后,默认无参构造器就会消失,这时候如果再写
Student s = new Student();
就会报错。所以建议自定义类都再提供一个无参构造器。
使用构造器创建对象
对属性的封装
要对用户的信息进行校验
练习
//Staff.java
package com.sakura.staff;
public class Staff {
private int num;
private char sex;
private double salary;
private String name;
public Staff(int a, String b, char c, double d){
this.num = a;
this.name = b;
this.sex = c;
this.salary = d;
}
public Staff(){}
void setinfo(int a,String b,char c,double d){
this.num = a;
this.name = b;
this.sex = c;
this.salary = d;
}
void getinfo(){
System.out.println("num = " + num);
System.out.println("name = " + name);
System.out.println("sex = " + sex);
System.out.println("salary = " + salary);
}
}
//Test.java
package com.sakura.staff;
public class Test {
public static void main(String[] args) {
Staff num1 = new Staff();
num1.setinfo(123,"sakura",'男',20000);
num1.getinfo();
Staff num2 = new Staff(666,"Alice",'女',10000);
num2.getinfo();
}
}
标准javabean
继承
1、使用继承要借用关键字extends
2、语法结构
[权限修饰符] 子类 extends 父类{}
3、当子类继承父类后就可以使用父类的资源
范例:
父类:
package com.sakura.jicheng;
public class Animal {
private String name;
private int age;
void setname(String name){
this.name = name;
}
void setAge(int age){
this.age = age;
}
void eat(){
System.out.println(this.name+"正在吃饭");
}
int getinfo_age(){
return this.age;
}
String getinfo_name(){
return this.name;
}
}
Cat类
package com.sakura.jicheng;
public class Cat extends Animal{
void miao(){
System.out.println("miao~miao~miao~");
}
}
Dog类
package com.sakura.jicheng;
public class Dog extends Animal{
void wang(){
System.out.println("wang wang wang");
}
}
Test类
package com.sakura.jicheng;
public class Test {
public static void main(String[] args) {
Cat cat = new Cat();
cat.setAge(8);
cat.setname("咪咪");
System.out.println(cat.getinfo_age());
System.out.println(cat.getinfo_name());
cat.miao();
Dog dog = new Dog();
dog.setAge(10);
dog.setname("大白");
System.out.println(dog.getinfo_age());
System.out.println(dog.getinfo_name());
dog.wang();
}
}
当出现同名变量时:this与super
super代表从父类继承下来的资源
继承资源的查找
父类的方法不能满足子类需求时,要进行方法重写
子类在使用资源时,优先在本类中查找,当本类中没有时,才去父类中查找,一点一点向上找,直到找到object类
object类是所有类的父类
方法的重写
1、当子类重写父类的方法时,访问权限不能比父类的访问权限更加严格,要>=父类的访问权限
2、返回值类型
当父类的返回类型是基本数据类型时,则子类必须与父类保持一致
当父类的返回类型是引用数据类型时,则子类可以是返回父类,也可以是返回子类
3、方法重写时,子类的形参必须与父类的形参保持一致,否则就相当于在子类中新增一个方法
4、子类不能抛出比父类更大的异常
this详解
this可以区分局部变量和成员变量
this可以调用本类中的构造器(是根据数据类型来匹配的,而不是形参名)
调用另一个构造器时,this必须放在本构造器首行,如本例中
this(name,age,salary);
就在首行
一般都是多参调少参。在本类中,this可省略
super详谈
每一个构造器首行都会有一个默认的隐藏的super,调用父类无参的构造器
当这种情况的时候,super是在少参的构造器中,第二个参数构造器的super()自动消失了
可以使用super()调用父类有参的构造器
可以使用super.调用父类的属性和方法
成员变量的赋值方法
代码块用 {}包裹
当是这种静态代码块时,代码块只执行一次
静态代码块:用于给静态变量进行赋值
静态代码只会执行一次,再次创建n个对象也不会执行。也是先于构造器执行
给成员变量赋值方式:
1.默认值
2.直接赋值
3.代码块赋值
4.get/set赋值
5、构造器赋值
静态变量不建议采用使用构造器赋值,因为它是属于类的,可以直接 类名.属性进行赋值
day10 面向对象
类的初始化
当有子类的初始化时,会先对父类进行初始化,再初始化子类
类的初始化不含子类
实例初始化不含子类
每次调用构造器,都会重复执行一次init方法
类的初始化含子类
混合初始化
多态的初识
封装:隐藏内部的实习细节,只对外暴露少量接口,供外界访问
方法:对功能的封装
类:对方法的封装
包:对模块的封装
继承:实现资源的复用
方法属性
多态:一个对象的多种形态
作用:可以让代码更加灵活
多态有两种状态(左边编译时状态 = 右边运行时状态):
1、编译时状态
2、运行时状态
多态创建的对象能够调用什么方法要看编译时状态
示例代码:
Animal类
package com.sakura.duotai;
public class Animal {
void eat(){
System.out.println("吃饭啦~~");
}
}
Cat类
package com.sakura.duotai;
public class Cat extends Animal{
void eat(){
System.out.println("猫吃鱼");
}
void catchMouse(){
System.out.println("猫抓老鼠");
}
}
Dog类
package com.sakura.duotai;
public class Dog {
void eat(){
System.out.println("狗吃骨头");
}
void lookHome(){
System.out.println("狗看家");
}
}
当我们用Animal类去new一个子类对象时,就是多态的一种体现
如图,输出的是猫重写的eat方法
但当我们尝试调用cat中其它方法时,就会报错
Animal a = new Cat();
/**这里的Animal a 就是编译时状态
new cat(); 是运行时状态
多态创建的对象能够调用什么方法要看编译时状态,代码跑起来时对象是谁,要看运行时状态**/
多态的作用一节省代码量
package com.sakura.duotai1;
public class Programmer {
void eat(){
System.out.println("程序员 干饭");
}
}
class Chinese extends Programmer{
void eat(){
System.out.println("中国人使用筷子吃饭");
}
void act(){
System.out.println("中国人会功夫");
}
}
class India extends Programmer{
void eat(){
System.out.println("印度人使用手吃饭");
}
void act(){
System.out.println("印度人摩托车玩的贼6");
}
}
class European extends Programmer{
void eat(){
System.out.println("欧洲人使用刀叉吃饭");
}
void act(){
System.out.println("欧洲人喜欢极限运动");
}
}
package com.sakura.duotai1;
public class Test {
public static void main(String[] args) {
Chinese chinese = new Chinese();
India india = new India();
European european = new European();
showEat(chinese);
showEat(india);
showEat(european);
}
public static void showEat(Programmer programmer){
programmer.eat();
}
}
这样写,节省了很多代码量
由于这里的Programmer programmer 是形参,所以会有
Programmer programmer = chinese/india/european;
满足父类的引用指向子类的对象
多态作用二存储不同类型数据
package com.sakura.duotai2;
public class Animal {
void eat(){
System.out.println("动物吃饭");
}
}
class Dog extends Animal{
void eat(){
System.out.println("猫吃鱼");
}
}
class Cat extends Animal{
void eat(){
System.out.println("狗吃肉");
}
}
package com.sakura.duotai2;
public class Test {
public static void main(String[] args) {
int [] arr = {10,20,30};//这是一个数组它只能存储同一种类型数据
Animal [] aniarr = new Animal[2];
Dog dog = new Dog();
Cat cat = new Cat();
aniarr[0] = dog;
aniarr[1] = cat;
for(Animal a:aniarr){
a.eat();
}
}
}
此处的cat和dog是不同类型的示例对象,但是都放在了同一个数组
多态应用三方法的返回值
示例代码:
Programmer.java
package com.sakura.duotai3;
public class Programmer {
void work(){
System.out.println("程序员 写代码");
}
}
class Chinese extends Programmer{
void work(){
System.out.println("中国 程序员写代码");
}
}
class India extends Programmer{
void work(){
System.out.println("印度 程序员写代码");
}
}
class European extends Programmer{
void work(){
System.out.println("欧洲 程序员写代码");
}
}
Guigu.java
package com.sakura.duotai3;
public class Guigu {
public static Programmer produce_Grammer(String country){
if("中国".equals(country)){
return new Chinese();
}else if("印度".equals(country)){
return new India();
}else if("欧洲".equals(country)){
return new European();
}
return null;
}
}
Test.java
package com.sakura.duotai3;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入您需要的程序员国家:");
Scanner input = new Scanner(System.in);
String country = input.next();
Programmer programmer = Guigu.produce_Grammer(country);
if (programmer != null) {
programmer.work();
} else {
System.out.println("还没有此国家程序员");
}
}
}
多态的练习一
Traffic.java
package com.sakura.duotai4;
public class Traffic {
public void drive(){
System.out.println("交通工具通行");
}
}
class Car extends Traffic{
public void drive(){
System.out.println("汽车奔驰在马路上");
}
}
class Bike extends Traffic{
public void drive(){
System.out.println("自行车在马路上缓慢的走着");
}
}
class Truck extends Traffic{
public void drive(){
System.out.println("货车满载着货物不快不慢的开着");
}
}
Test.java
package com.sakura.duotai4;
public class Test {
public static void main(String[] args) {
Traffic [] trarr =new Traffic[3];
trarr[0] = new Car();
trarr[1] = new Bike();
trarr[2] = new Truck();
for(Traffic a:trarr){
a.drive();
}
}
}
多态的练习二
示例代码:
Employee.java
package com.sakura.duotai5;
public class Employee {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double earning(){
return 0;
}
public String getinfo(){
return "姓名是:"+name+" ,实发工资"+earning();
}
public Employee(){};
public Employee(String name) {
this.name = name;
}
}
SalaryEmployee.java
package com.sakura.duotai5;
public class SalaryEmployee extends Employee{
private double salary;
private int workday;
private int offday;
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getWorkday() {
return workday;
}
public void setWorkday(int workday) {
this.workday = workday;
}
public int getOffday() {
return offday;
}
public void setOffday(int offday) {
this.offday = offday;
}
public SalaryEmployee(){};
public SalaryEmployee(double salary, int workday, int offday,String name) {
super(name);
this.salary = salary;
this.workday = workday;
this.offday = offday;
}
@Override
public double earning() {
return (getSalary()-getSalary()/getWorkday()*getOffday());
}
}
Manager.java
package com.sakura.duotai5;
public class Manager extends SalaryEmployee{
private double part;
public double earning(){
return (getSalary()-getSalary()/getWorkday()*getOffday()*(1+part));
}
public Manager(){}
public Manager(double salary, int workday, int offday, String name, double part) {
super(salary, workday, offday, name);
this.part = part;
}
}
HourEmployee.java
package com.sakura.duotai5;
public class HourEmployee extends Employee{
private int hours;
private int hourmoney;
public int getHours() {
return hours;
}
public void setHours(int hours) {
this.hours = hours;
}
public int getHourmoney() {
return hourmoney;
}
public void setHourmoney(int hourmoney) {
this.hourmoney = hourmoney;
}
public double earning(){
return getHours()*getHourmoney();
}
public HourEmployee(){}
public HourEmployee(String name, int hours, int hourmoney) {
super(name);
this.hours = hours;
this.hourmoney = hourmoney;
}
}
Test.java
package com.sakura.duotai5;
public class Test {
public static void main(String[] args) {
Employee [] employee = new Employee[5];
SalaryEmployee s1 = new SalaryEmployee(10000,20,5,"蜡笔小新");
SalaryEmployee s2 = new SalaryEmployee(15000,20,5,"张伟");
HourEmployee h1 = new HourEmployee("苦逼打工人",30,15);
HourEmployee h2 = new HourEmployee("小王",50,30);
Manager m1 = new Manager(20000,22,3,"霸道总裁",0.9);
employee[0] = s1;
employee[1] = s2;
employee[2] = h1;
employee[3] = h2;
employee[4] = m1;
for(Employee a:employee){
System.out.println(a.getinfo());
}
}
}
向下转型
多态的向上转型和向下转型都是都是针对于编译时类型 运行时类型从始至终不会发生改变
父类的引用指向子类的示例 就是向上转型(弊端:无法使用子类独有资源):
Animal ani = new Cat();
向下转型:
使用子类自己独有的资源时 down casting
类似于强制类型转换
向下转型前提:已经完成了向上转型
instanceof
判断左边的对象是否属于右边类型
day11
非虚方法
native关键字
final关键字
Object类
to_string
原方法
重写后
直接alt+insert添加即可
getClass()
获取运行时类型
finalize
hashcode
用于返回当前对象的hash码
重写hashcode()方法,尽量让不同对象产生的hash码不一样
equals()
equals 只能比较引用类型数据
空指针异常
抽象初识
抽象注意点
接口初识
如何声明接口:
接口:定义规范
接口也有多态
注意:
接口中的抽象方法默认被 public abstract 修饰
接口中的全局静态常量默认被
这三个修饰
一个类可以实现多个接口
一个类实现接口后,如果不想实现接口中的抽象方法,则自己必须变为抽象类
添加默认方法:
这个方法不是每个实现这个接口的类都必须要重写的,按需使用。比如飞机和小鸟,只有飞机需要加油,小鸟并不需要。
添加静态方法:
接口也可以进行多继承:
一个类可以先继承一个父类,再去实现多个接口,顺序不能改变,必须先继承再改变
接口的非正常情况
这两个接口有重名的方法,当实现的时候就会报错
解决方法:在类中重写 study方法
但是,但我们想要调用接口的study方法该怎么办?
重写study后这样调用:
comparable接口
使用comparable接口完成引用数据类型的比较
需要实现:
重写Comparable
day12 面向对象
comparable接口-内部比较器
package com.sakura.neibu;
public class Test {
public static void main(String[] args) {
Person p1 = new Person("李白",40);
Person p2 = new Person("杜甫",30);
int i = p1.compareTo(p2);
if(i>0){
System.out.println(p1.name+">"+p2.name);
}else if(i<0){
System.out.println(p1.name+"<"+p2.name);
}else {
System.out.println(p1.name+"="+p2.name);
}
}
}
class Person implements Comparable{
@Override
public int compareTo(Object o) {
Person p = (Person)o;
return this.age-p.age;
}
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Comparator接口-外部比较器
代码范例:
Person.java
package com.sakura.waibu;
public class Person {
String name;
int age;
double salary;
public Person(String name, int age, double salary) {
this.name = name;
this.age = age;
this.salary = salary;
}
public Person() {
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
PerSortOfAge.java
package com.sakura.waibu;
import java.util.Comparator;
public class PersonSortOfAge implements Comparator {
@Override
public int compare(Object o1, Object o2) {
Person p1 = (Person)o1;
Person p2 = (Person)o2;
return p1.age-p2.age;
}
}
Test.java
package com.sakura.waibu;
public class Test {
public static void main(String[] args) {
Person p1 = new Person("李白",60,6666.55);
Person p2 = new Person("杜甫",58,8888);
PersonSortOfAge sortOfAge = new PersonSortOfAge();
int res = sortOfAge.compare(p1,p2);
if(res > 0){
System.out.println(p1.name+">"+p2.name);
}else if(res < 0){
System.out.println(p2.name+"<"+p1.name);
}else {
System.out.println(p1.name+"="+p2.name);
}
}
}
枚举
枚举初识
示例代码:
Season.java
package com.sakura.enum2;
public enum Season {
SPRING("春暖花开","春天"),
SUMMER("夏日炎炎","夏天"),
AUTUMN("秋高气爽","秋天"),
WINTER("白雪恺恺","冬天");
private String des;
private String name;
Season(String des, String name) {
this.des = des;
this.name = name;
}
Season() {
}
@Override
public String toString() {
return "Season{" +
"des='" + des + '\'' +
", name='" + name + '\'' +
'}';
}
}
test.java
package com.sakura.enum2;
public class test {
String name = "word";
int num = 200;
Season season = Season.SPRING;
public static void main(String[] args) {
test one =new test();
System.out.println("one.name = " + one.name);
System.out.println("one.season = " + one.season.name());
System.out.println("one.num = " + one.num);
}
}
枚举结束
使用switch语句来判断是哪个枚举:
TestSwitch.java
package com.sakura.enum2;
public class TestSwitch {
public static void main(String[] args) {
Season season = Season.SPRING;
switch (season){
case SPRING:
System.out.println("温暖");
break;
case SUMMER:
System.out.println("炎热");
case AUTUMN:
System.out.println("舒适");
break;
case WINTER:
System.out.println("寒冷");
break;
}
}
}
枚举实现接口
Gender.java
package com.sakura.enum3;
public enum Gender implements Run{
MAN{
@Override
public void run() {
System.out.println("男士 大步走");
}
},WOMAN{
@Override
public void run() {
System.out.println("女士 不紧不慢的走");
}
};
}
interface Run{
void run();
}
Test.java
package com.sakura.enum3;
public class Test {
public static void main(String[] args) {
Gender people = Gender.MAN;
people.run();
}
}
练习
示例代码:
Month.java
package com.sakura.enum4;
public enum Month {
JANUARY(1,"这是一月"),
FEBRUARY(2,"这是二月"),
March(3,"这是三月"),
APRIL(4,"这是四月"),
MAY(5,"这是五月"),
JUNE(6,"这是六月"),
JULY(7,"这是七月"),
AUGUST(8,"这是八月"),
SEPTEMBER(9,"这是九月"),
OCTOBER(10,"这是十月"),
NOVEMBER(11,"这是十一月"),
DECEMBER(12,"这是十二月");
private int value;
private String des;
Month(int value, String des) {
this.value = value;
this.des = des;
}
Month() {
}
@Override
public String toString() {
return "Month{" +
"value=" + value +
", des='" + des + '\'' +
'}';
}
}
Test.java
package com.sakura.enum4;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
System.out.println("请输入您要获取月份所对应的数字:");
Scanner input = new Scanner(System.in);
int num = input.nextInt();
getByValue(num);
}
public static Month getByValue(int value){
switch (value){
case 1:
System.out.println(Month.JANUARY);
break;
case 2:
System.out.println(Month.FEBRUARY);
break;
case 3:
System.out.println(Month.March);
break;
case 4:
System.out.println(Month.APRIL);
break;
case 5:
System.out.println(Month.MAY);
break;
case 6:
System.out.println(Month.JUNE);
break;
case 7:
System.out.println(Month.JULY);
break;
case 8:
System.out.println(Month.AUGUST);
break;
case 9:
System.out.println(Month.SEPTEMBER);
break;
case 10:
System.out.println(Month.OCTOBER);
break;
case 11:
System.out.println(Month.NOVEMBER);
break;
case 12:
System.out.println(Month.DECEMBER);
break;
}
return Month.JANUARY; # 这个地方的return只是为了避免报错,无特殊含义
}
}
包装类初识
Java提供了两个类型系统,基本类型与引用类型,使用基本类型在于效率,然而当要使用只针对对象设计的API或新特性(例如泛型),那么基本数据类型的数据就需要用包装类来包装。
比如Integer有很多方法
test.java
package com.sakura.wrapper;
public class test {
public static void main(String[] args) {
int a = 100;
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
String s1 = Integer.toBinaryString(a);
String s2 =Integer.toHexString(a);
System.out.println("s1 = " + s1);
System.out.println("s2 = " + s2);
}
}
自动装箱和自动拆箱
基本数据类型转化为包装类型数据:
老方法:
方式一:通过构造器
Integer 标识符 = new Integer(基本数据类型);
如:
int a = 10;
Integer i1 = new Integer(a);
方法二
Integer 标识符 = Integer.valueOf(基本数据类型);
如:
int a = 10;
Integer i2 = Integer.valueOf(a);
新方法:
自动装箱
Integer in = 基本数据类型;
自动装箱底层采用的是 IntegerOf.valueOf(a);
包装类型数据转化为基本类型数据:
Integer i4 = new Integer(20);
方法一:调用包装类对象的 intValue();
int i = i4.intValue();
方法二:自动拆箱
自动将引用数据类型变为基本数据类型
int i =i4;
基本类型与包装类型与字符串之间的转换
1、字符串—>基本数据类型
Integer.parseInt(“字符串纯数字”); 如果不是纯数字,会报异常,NumberFormatException
示例代码:
test.java
package com.sakura.wrapper2;
import java.util.Scanner;
public class test {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("请输入一个数字:");
String a = input.next();
int b = Integer.parseInt(a);
System.out.println("b = " + b);
}
}
方法二:
Integer i = new Integer("字符串纯数字");
注意char中没有此类方法:
"AB".charAt(1); 0代表第一个字符,1代表第二个字符
2、基本类型数据转为字符串
方法一:
int a = 10;
String ss = ""+a;
方法二:
int b = 20;
string i = String.valueOf(b);
对应包装类型的缓存区
包装类型数据,只能接受对应的包装类型,不能再采用类型自动提升
包装类型有一个缓存区,超过这个区域,就会去new一个包装类
示例代码:
public class test {
public static void main(String[] args) {
Integer a = 100;
Integer b = 100;
System.out.println("1----->" + (a==b));
Integer c = 1000;
Integer d = 1000;
System.out.println("2------>"+(c==d));
}
}
静态内部类
什么是内部类?
将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。
作用:
1.可以打破java单继承的限制
2.在内部类中做更多的功能为外部类服务
3.可以资源的隐藏
特点:
静态内部类可以访问静态外部类资源
静态的属性,静态的方法
修饰:
外部类只能被public和public修饰,内部类无限制
语法结构:
class 外部类名{
[权限修饰符四种] static [final] class 内部类名{
}
}
非静态内部类
不加static修饰的内部类
class 外部类名{
[权限修饰符四种] class 内部类名{
}
}
特点:
day13
局部内部类
不是重点
匿名内部类的声明
匿名内部类:没有名字的类
匿名对象:没有名字的对象
方式一:
new 父类(){
重写父类方法
}
创建了一个子类,但是子类没有名字
方式二:
new 父类(实参列表){
重写父类方法
}
创建了一个子类,但是子类没有名字
方式三:
new 父接口(){
重写父类方法
}
创建了一个子类,但是子类没有名字
方式四:
new 父抽象类(){
重写父类方法
}
创建了一个子类,但是子类没有名字
示例代码:
package com.sakura.innerclass.anosclass;
import org.junit.Test;
interface Run{
void run();
}
abstract class Animal{
abstract void eat();
}
public class TestLocal {
@Test
public void test01(){
new Father(){
@Override
public void show() {
System.out.println("this is new show-1()");
}
};
}
@Test
public void test02(){
new Father(30){
@Override
public void show() {
System.out.println("this is new show-2(30)");
}
};
}
@Test
public void test03(){
new Run(){
@Override
public void run() {
System.out.println("this is new Run");
}
};
}
@Test
public void test04(){
new Animal(){
@Override
void eat() {
System.out.println("this is new eat()");
}
}
}
}
class Father{
int age;
String name;
public Father(int age){
this.age=age;
}
public Father(){
}
public void show(){
System.out.println("this is father show(");
}
}
匿名内部类的使用
package com.sakura.innerclass.anosclass;
import org.junit.Test;
interface Fly{
void fly();
}
public class TestLocal2 {
@Test
public void test03(){
method(new Fly(){
@Override
public void fly() {
System.out.println("超人会飞");
}
});
}
public static void method(Fly fly) {
fly.fly();
}
@Test
public void test01(){
new Father(){
@Override
public void show() {
System.out.println("this is new Father show()");
}
}.show();
}
@Test
public void test02(){
Father father = new Father(99){
@Override
public void show() {
System.out.println("this is new Father show-2()");
}
};
father.show();
father.test();
System.out.println(father.num);
}
}
class Father{
int num;
public Father(int num) {
this.num = num;
}
public Father() {
}
public void test(){
System.out.println("this is Father test");
}
public void show(){
System.out.println("this is Father show()");
}
}
·
匿名内部类练习一
Employee.java
package com.sakura.innerclass.eaer;
public class Employee {
private int num;
private String name;
private double salary;
public Employee(int num, String name, double salary) {
this.num = num;
this.name = name;
this.salary = salary;
}
public void setNum(int num) {
this.num = num;
}
public void setName(String name) {
this.name = name;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getNum() {
return num;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
@Override
public String toString() {
return "Employee{" +
"num=" + num +
", name='" + name + '\'' +
", salary=" + salary +
'}';
}
public Employee() {
}
}
Test.java
package com.sakura.innerclass.eaer;
import java.util.Arrays;
import java.util.Comparator;
public class Test {
public static void main(String[] args) {
Employee e1 = new Employee(1,"李白",5489.21);
Employee e2 = new Employee(2,"杜甫",6984.66);
Employee e3 = new Employee(3,"白居易",8888.666);
Employee e4 = new Employee(4,"苏轼",4569.44);
Employee e5 = new Employee(5,"李清照",8999.99);
Employee[] employees = {e1,e2,e3,e4,e5};
// SortEmployee sortEmployee = new SortEmployee();
System.out.println("排序前");
arrayprint(employees);
System.out.println("排序后");
Arrays.sort(employees, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Employee e1 = (Employee)o1;
Employee e2 = (Employee)o2;
return Double.compare(e1.getSalary(),e2.getSalary());
}
});
arrayprint(employees);
}
public static void arrayprint(Employee[] e){
for (Employee employee : e) {
System.out.println(employee);
}
}
}
这里使用了匿名内部类,要重点关注
运行结果:
注解
项目:客户信息管理系统
需求
开发简单架构
day14
异常体系
异常的演示
package com.sakura.exception;
import org.junit.Test;
public class test1 {
@Test
public void arryException(){
int[] arr = {1,2,3};
try {
System.out.println(arr[3]);
}catch (ArrayIndexOutOfBoundsException e){
e.printStackTrace(); //打印异常信息
e.getMessage(); //获取异常位置
System.out.println("该行代码已执行!");
}
}
}
使用try catch处理异常
但是这种写起来比较麻烦,如果采用了多层catch,我们可以省略为一个Exception
try{
}catch(xxx){
}catch(xxx){
}catch(Exception e){
}
使用try catch finally处理异常
使用throw和throws处理异常
示例代码一:
package com.sakura.exception.throwexception;
public class ThrowException2 {
public static void main(String[] args) {
try{
showMessage(4);
}catch (ArrayIndexOutOfBoundsException e){
System.err.println(e.getMessage());
System.out.println("这行也执行啦");
}
}
public static void showMessage(int index){
int [] arr = {1,2,3};
if(index <0 || index >= arr.length){
throw new ArrayIndexOutOfBoundsException("数组下标越界了!");
}
System.out.println(arr[index]);
}
}
此为运行时异常:
示例代码二:
package com.sakura.exception.throwexception;
import java.io.File;
import java.io.FileNotFoundException;
public class ThrowException {
public static void main(String[] args) {
try {
showMessage();
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public static void showMessage() throws FileNotFoundException{
File file = new File("C:\\Users\\Sakura\\Desktop\\图片\\love.jpg");
boolean exists = file.exists();
if(!exists){
throw new FileNotFoundException("文件不存在o");
}
System.out.println(exists);
}
}
这里是一个编译时异常,必须在方法名后throw异常
异常类方法重写
如,此时子类的异常比父类大就会报错,将异常换位置即可!
自定义异常的方式
day15
多线程简介
如何编写多线程程序?
- 继承thread类
- 实现Runnable接口
- 实现Callable接口
- 线程池
实现多线程方式一:继承Thread类
创建两条线程:
采用继承的方式创建多线程
- 创建一个类继承Thead
- 重写run方法,多线程会执行重写的方法
- 启动线程:线程对象.start()
Thread.currentThead().getName() # 获取当前线程名称
Test.java
package com.sakura.thread.extendthread;
public class Test1 {
public static void main(String[] args) {
Thread.currentThread().setName("这是线程一"); //设置主线程的名字
RabbitThead rabbitThead = new RabbitThead(); //创建对象
rabbitThead.setName("这是线程二"); //设置第二个线程名字
rabbitThead.start(); //启动rabbitThead线程
while (true){
System.out.println(Thread.currentThread().getName()+"乌龟正在跑");
}
}
}
RabbitThread.java
package com.sakura.thread.extendthread;
public class RabbitThead extends Thread{
public void run(){
while (true){
System.out.println(Thread.currentThread().getName()+"兔子正在跑");
}
}
}
运行结果:
创建多线程方式二:实现Runnable接口
- 创建一个对象实现 Runnable接口
- 重写run方法
- 创建 Runnable对象
- 创建Thread对象 将 Runnable对象作为参数传递
- 调用start()方法,启动线程
继承Thread类与实现Runnable接口创建多线程方法对比:
- 继承的方式简单
- 实现Runnable接口可以更好的实现资源共享
示例代码:
Test.java
package com.sakura.thread.runnablethread;
public class Test {
public static void main(String[] args) {
Thread.currentThread().setName("这是线程一");
//1.创建Runnable对象
RabbitRunnable rabbitRunnable = new RabbitRunnable();
//2.创建Thead类,将 Runnable对象作为参数传递
Thread t1 = new Thread(rabbitRunnable);
t1.setName("这是线程二"); //设置线程二名字
t1.start(); //开启线程
while (true){
System.out.println(Thread.currentThread().getName()+"乌龟跑");
}
}
}
RabbitRunnable.java
package com.sakura.thread.runnablethread;
public class RabbitRunnable implements Runnable{
@Override
public void run() {
while (true){
System.out.println(Thread.currentThread().getName()+"兔子跑");
}
}
}
运行结果:
采用匿名内部类的方式创建多线程程序
示例代码:
package com.sakura.thread;
import org.junit.Test;
public class AnonymousTest {
public static void main(String[] args) {
new Thread(){
@Override
public void run() {
while (true){
System.out.println("乌龟跑");
}
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
System.out.println("兔子跑");
}
}
}).start();
}
}
使用构造器赋值线程名
一、继承Thread类构造器
使用继承的方式,可以采用this调用父类资源getName()
package com.sakura.thread;
public class Test1 {
public static void main(String[] args) {
RabbitThread1 t1 = new RabbitThread1("小白兔");
RabbitThread1 t2 = new RabbitThread1("小灰兔");
t1.start();
t2.start();
}
}
class RabbitThread1 extends Thread{
public RabbitThread1(String name) {
super(name);
}
@Override
public void run() {
for (int i = 0;i<5;i++){
System.out.println(this.getName()+"正在跑");
}
}
}
调用父类构造器
二、继承Runnable接口
package com.sakura.thread;
public class Test2 {
public static void main(String[] args) {
ToriseThread toriseThread = new ToriseThread();
Thread t1 = new Thread(toriseThread,"绿毛龟");
Thread t2 = new Thread(toriseThread,"杰尼龟");
t1.start();
t2.start();
}
}
class ToriseThread implements Runnable{
@Override
public void run() {
for (int i = 0;i<5;i++){
System.out.println(Thread.currentThread().getName()); //继承Runnable无法调用this
}
}
}
线程常用方法
构造方法:
常用方法系列:
构造器设置名字:
Test.java
package com.sakura.thread;
public class Test {
public static void main(String[] args) {
RabbitThread rabbitThread = new RabbitThread();
Thread t1 = new Thread(rabbitThread,"小白兔");
Thread t2 = new Thread(rabbitThread,"小黑兔");
System.out.println("t1.isAlive()="+t1.isAlive());
System.out.println("t2.isAlive()="+t2.isAlive());
t1.start();
t2.start();
System.out.println("t1.isAlive()="+t1.isAlive());
System.out.println("t2.isAlive()="+t2.isAlive());
}
}
class RabbitThread implements Runnable{
@Override
public void run() {
while (true){
System.out.println(Thread.currentThread().getName()+"正在跑");
}
}
}
设置优先级:
setPriority(优先级):
1<= 优先级 <=10
// 如果没有指定,线程的默认优先级为5
// 优先级低也会执行,也有执行机会
Test.java
package com.sakura.thread;
public class Test {
public static void main(String[] args) {
RabbitThread rabbitThread = new RabbitThread();
Thread t1 = new Thread(rabbitThread,"小白兔");
Thread t2 = new Thread(rabbitThread,"小黑兔");
t1.setPriority(10);
t2.setPriority(1);
t1.start();
t2.start();
}
}
class RabbitThread implements Runnable{
@Override
public void run() {
for(int i =0;i<20;i++){
System.out.println(Thread.currentThread().getName()+"正在跑");
}
}
}
输出结果:
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小黑兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小白兔正在跑
小黑兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
设置睡眠:
Test.java
package com.sakura.thread;
public class Test {
public static void main(String[] args) {
RabbitThread rabbitThread = new RabbitThread();
Thread t1 = new Thread(rabbitThread,"小白兔");
Thread t2 = new Thread(rabbitThread,"小黑兔");
t1.setPriority(10);
t2.setPriority(1);
t1.start();
t2.start();
}
}
class RabbitThread implements Runnable{
@Override
public void run() {
for(int i =0;i<100;i++){
//run方法出现异常只能采用 try{}catch{}方式处理 因为子类不能抛出比父类更大的异常
//而Runnable中没有抛出异常
try {
Thread.sleep(1000); //单位是毫秒
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"正在跑");
}
}
}
使用join方法插队:
插队的线程调用join(2000)那么被插队的线程要进行等待 2000ms等插队的线程执行完毕后或者等待时间已到那么继续执行
package com.sakura.thread;
public class Test {
public static void main(String[] args) {
RabbitThread rabbitThread = new RabbitThread();
Thread t1 = new Thread(rabbitThread,"小白兔");
t1.start();
for(int i=0;i<20;i++){
if (i==10){
try {
t1.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("主线程跑\t"+i);
}
}
}
class RabbitThread implements Runnable{
@Override
public void run() {
for(int i =0;i<20;i++){
System.out.println(Thread.currentThread().getName()+"\t正在跑\t"+i);
}
}
}
输出:
主线程跑 0
主线程跑 1
主线程跑 2
主线程跑 3
主线程跑 4
主线程跑 5
主线程跑 6
主线程跑 7
主线程跑 8
小白兔 正在跑 0
主线程跑 9
小白兔 正在跑 1
小白兔 正在跑 2
小白兔 正在跑 3
小白兔 正在跑 4
小白兔 正在跑 5
小白兔 正在跑 6
小白兔 正在跑 7
小白兔 正在跑 8
小白兔 正在跑 9
小白兔 正在跑 10
小白兔 正在跑 11
小白兔 正在跑 12
小白兔 正在跑 13
小白兔 正在跑 14
小白兔 正在跑 15
小白兔 正在跑 16
小白兔 正在跑 17
小白兔 正在跑 18
小白兔 正在跑 19
主线程跑 10
主线程跑 11
主线程跑 12
主线程跑 13
主线程跑 14
主线程跑 15
主线程跑 16
主线程跑 17
主线程跑 18
主线程跑 19
如果我们设置下等待时间:
package com.sakura.thread;
public class Test {
public static void main(String[] args) {
RabbitThread rabbitThread = new RabbitThread();
Thread t1 = new Thread(rabbitThread,"小白兔");
t1.start();
for(int i=0;i<20;i++){
if (i==10){
try {
t1.join(2000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("主线程跑\t"+i);
}
}
}
class RabbitThread implements Runnable{
@Override
public void run() {
for(int i =0;i<20;i++){
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"\t正在跑\t"+i);
}
}
}
此时输出结果:
主线程跑 0
主线程跑 1
主线程跑 2
主线程跑 3
主线程跑 4
主线程跑 5
主线程跑 6
主线程跑 7
主线程跑 8
主线程跑 9
主线程跑 10
主线程跑 11
主线程跑 12
主线程跑 13
主线程跑 14
主线程跑 15
主线程跑 16
主线程跑 17
主线程跑 18
主线程跑 19
小白兔 正在跑 0
小白兔 正在跑 1
...
常用方法系列二
yield()方法-线程的礼让
所谓线程的礼让不过是从运行状态先回到就绪状态,事实上,当优先级相同时,它们仍然具有相同的概率被调用!
示例代码:
package com.sakura.thread.method;
public class Test {
public static void main(String[] args) {
RabbitThread rabbitThread = new RabbitThread();
Thread t1 = new Thread(rabbitThread,"小灰兔");
t1.start();
for (int i =0; i<20;i++){
if (i==5){
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+"\t正在运行\t"+i);
}
}
}
class RabbitThread implements Runnable{
@Override
public void run() {
for(int i = 0; i<20; i++){
System.out.println(Thread.currentThread().getName()+"\t正在运行\t"+i);
}
}
}
stop()与setDaemon(true)
stop() //结束线程
setDaemon(true) //守护线程
setDaemon的示例用法:
package com.sakura.thread.method;
public class Test {
public static void main(String[] args) {
RabbitThread rabbitThread = new RabbitThread();
Thread t1 = new Thread(rabbitThread,"小灰兔");
t1.setDaemon(true);
t1.start();
for (int i =0; i<30;i++){
System.out.println(Thread.currentThread().getName()+"\t正在运行\t"+i);
}
}
}
class RabbitThread implements Runnable{
@Override
public void run() {
while (true){
System.out.println(Thread.currentThread().getName()+"\t正在运行\t");
}
}
}
t1进程是主进程的守护进程,当主进程停止时,t1也会随之停止
volatile
volatile的作用是确保不会因编译器的优化而省略某些指令,volatile的变量是说这变量可能会被意想不到地改变,每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份,这样,编译器就不会去假设这个变量的值了。
示例代码:
package com.sakura.thread.method;
public class Test {
public volatile static boolean flag = true; //当没有加volatile程序不会结束,加上后才会结束
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
while (flag){
// System.out.println("程序执行中~~~");
}
}
}).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
flag = false;
}
}
线程安全
线程安全问题:当多个线程操作共享数据时有可能会发生线程安全问题
解决线程安全问题:
同步代码块
同步方法
Lock : 公平锁 非公平锁 juc
模拟火车站卖票,体现线程安全问题:
问题代码:
package com.sakura.thread.ticket;
public class Test {
public static void main(String[] args) {
TicketThread ticketThread1 = new TicketThread("售票点一");
TicketThread ticketThread2 = new TicketThread("售票点二");
TicketThread ticketThread3 = new TicketThread("售票点三");
ticketThread1.start();
ticketThread2.start();
ticketThread3.start();
}
}
class TicketThread extends Thread{
public TicketThread(String name) {
super(name);
}
@Override
public void run() {
int count = 100;
while (true){
if (count <= 0){
break;
}
System.out.println(Thread.currentThread().getName()+"已卖出第"+count+"票!");
count--;
}
}
}
我们可以发现卖的票有重复的,我们本想要卖100张,因为多线程我们实际卖了300张。
使用同步代码块解决线程安全问题
出现的问题出现了0票或者重复的票,需要有一个监视器查看卖票的数据
解决方式一:使用同步代码块:
synchronized(同步监视器对象){
} //同步监视器对象必须是引用数据类型,当多条线程操作共享数据同步监视器对象必须是同一个
保证在同步代码块内只有一条线程在执行其他线程需要在同步代码块外等待
package com.sakura.thread.ticket;
public class Test {
public static void main(String[] args) {
TicketThread ticketThread1 = new TicketThread("售票点一");
TicketThread ticketThread2 = new TicketThread("售票点二");
TicketThread ticketThread3 = new TicketThread("售票点三");
ticketThread1.start();
ticketThread2.start();
ticketThread3.start();
}
}
class TicketThread extends Thread{
static int count = 100;
public TicketThread(String name) {
super(name);
}
@Override
public void run() {
while (true) {
synchronized (TicketThread.class) {
if (count <= 0) {
break;
}
System.out.println(this.getName() + "已卖出第" + count + "票!");
count--;
}
}
}
}
输出结果:
ps:当一条线程进入同步代码块内,那么其他线程不能进入拥有同一个同步监视器对象的同步代码块
使用同步方法解决线程安全问题
有一条线程进入同步方法那么其他线程不仅不能进入此方法也不能进入拥有同一个同步监视器对象的同步方法
示例代码:
package com.sakura.thread.ticket;
public class Test {
public static void main(String[] args) {
TicketThread ticketThread = new TicketThread();
Thread t1 = new Thread(ticketThread,"售票点一");
Thread t2 = new Thread(ticketThread,"售票点二");
Thread t3 = new Thread(ticketThread,"售票点三");
t1.start();
t2.start();
t3.start();
t2.setPriority(10);
t1.setPriority(1);
}
}
class TicketThread implements Runnable{
int count = 100;
@Override
public void run() {
while (true){
if (count <=0){
return;
}
saleTicket();
}
}
private synchronized void saleTicket(){
if (count <=0){
return;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName()+"第"+count+"票已卖出");
count--;
}
}
使用同步代码块解决线程安全问题-练习题
package com.sakura.thread;
import java.util.Scanner;
public class AccountTest {
public static void main(String[] args) {
AccountRunnable account = new AccountRunnable();
Thread t1 = new Thread(account,"HJY");
Thread t2 = new Thread(account,"WYF");
t1.start();
t2.start();
}
}
class Account{
int balance = 600;
public void withMoney(int money){
balance -= money;
}
}
class AccountRunnable implements Runnable{
Account account = new Account();
@Override
public void run() {
synchronized (account){
if (account.balance < 500){
System.out.println(Thread.currentThread().getName()+"\t您的余额不足,取款失败\t"+account
.balance);
}else {
account.withMoney(500);
System.out.println(Thread.currentThread().getName()+"\t恭喜您\t"+"已成功取出500元"+"您的余额为"+account.balance);
}
}
}}
单例模式
饿汉式:
示例代码:
package com.sakura.thread.single;
public class Test {
public static void main(String[] args) {
Single s1 = Single.INSTANCE;
Single s2 = Single.INSTANCE;
System.out.println(s1==s2);
Single1 s3 = Single1.INSTANCE;
Single1 s4 = Single1.INSTANCE;
System.out.println(s3==s4);
}
}
class Single{
public static final Single INSTANCE = new Single(); //提前将对象创建了出来
private Single() {
}
}
enum Single1 {
INSTANCE
}
懒汉式:
package com.sakura.thread.single;
public class Test {
public static void main(String[] args) {
LazyGuys s1 = LazyGuys.withsingle();
LazyGuys s2 = LazyGuys.withsingle();
System.out.println(s1==s2);
}
}
class LazyGuys{
private LazyGuys(){}
private static LazyGuys lazyGuys;
public synchronized static LazyGuys withsingle(){
if (lazyGuys == null){
synchronized (Test.class){
LazyGuys lazyGuys = new LazyGuys();
}
}
return lazyGuys;
}
}
day16
线程通信的初识
多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。而多个线程并发执行时,在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行,那么多线程之间需要一些通信机制,可以协调它们的工作,以此来帮我们达到多线程共同操作一份数据。
比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,此时B线程必须等到A线程完成后才能执行,那么线程A与线程B之间就需要线程通信,即等待唤醒机制
线程通信采用同步代码实现
示例代码:
package com.sakura.thread.notify;
public class Test {
public static void main(String[] args) {
Bar bar = new Bar();
CookerThread c1 = new CookerThread(bar);
WaiterThread w1 = new WaiterThread();
w1.setBar(bar);
c1.setName("五星级大厨");
w1.setName("海底捞服务员");
c1.start();
w1.start();
}
}
class Bar{
int count = 0;
public static final int MAX_ENUM = 10;
}
class CookerThread extends Thread{
Bar bar;
public CookerThread(Bar bar) {
this.bar = bar;
}
@Override
public void run() {
while (true) {
synchronized (bar) {
if (bar.count >= bar.MAX_ENUM) {
try {
bar.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
bar.count++;
System.out.println(Thread.currentThread().getName() + "正在做菜中,这是第" + bar.count + "份菜");
bar.notify();
}
}
}
}
class WaiterThread extends Thread{
private Bar bar;
public void setBar(Bar bar) {
this.bar = bar;
}
@Override
public void run() {
while (true) {
synchronized (bar) {
if (bar.count <= 0) {
try {
bar.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
bar.count--;
System.out.println(Thread.currentThread().getName() + "正在端菜中,端走后还有" + bar.count + "份菜");
bar.notify();
}
}
}
}
死锁
产生死锁的原因两条线程互相持有对方的锁资源不放松,可以让一条线程先跑完另一条线程再开始
示例代码:
package com.sakura.thread.deadlock;
public class Test {
public static void main(String[] args) {
Object goods = new Object();
Object money = new Object();
CustomerThread customerThread = new CustomerThread(goods, money);
GoodsThread goodsThread = new GoodsThread(goods, money);
customerThread.setName("供应商");
goodsThread.setName("采购商");
customerThread.start();
goodsThread.start();
}
}
class CustomerThread extends Thread{
Object goods;
Object money;
public CustomerThread(Object goods, Object money) {
this.goods = goods;
this.money = money;
}
@Override
public void run() {
synchronized (goods){
System.out.println(Thread.currentThread().getName()+":你奶奶滴,先发货再给钱");
synchronized (money){
System.out.println(Thread.currentThread().getName()+":已付钱");
}
}
}
}
class GoodsThread extends Thread{
Object goods;
Object money;
public GoodsThread(Object goods, Object money) {
this.goods = goods;
this.money = money;
}
@Override
public void run() {
synchronized (money){
System.out.println(Thread.currentThread().getName()+":你奶奶滴,先给钱再发货");
synchronized (goods){
System.out.println(Thread.currentThread().getName()+":已发货");
}
}
}
}
此时便形成了死锁
如何解决?
在两个启动线程的代码中间,使主线程睡眠一段时间,即可避免
线程的生命周期
观点一
观点二
基础api与常见算法
和数学相关的类
java.lang.Math
abs: 求绝对值
ceil: 向上取整
floor: 向下取整
random(): 随机数 [0,1) 左闭右开
n 较大的数 m 较小的数
[m,n] ----> (int)(Math.random()*(n-m+1)+m);
pow(n,y) : n^y
sqrt() :开平方
round(): 四舍五入
示例代码:
package com.sakura.api;
public class MathTest {
public static void main(String[] args) {
System.out.println(Math.abs(-10));
System.out.println(Math.ceil(3.00001));
System.out.println(Math.floor(1.999999));
System.out.println(Math.random());
int n = 100;
int m = 55;
System.out.println((int)(Math.random()*(n-m+1)));
System.out.println(Math.pow(2, 4));
System.out.println(Math.sqrt(64));
System.out.println(Math.round(5.4999));
System.out.println(Math.round(5.5));
}
}
BigInteger类
存储大的整数
示例代码:
package com.sakura.api;
import java.math.BigInteger;
public class Test1 {
public static void main(String[] args) {
BigInteger bigInteger = new BigInteger("999999999998484844554544545");
System.out.println(bigInteger);
BigInteger b1 = new BigInteger("300");
BigInteger b2 = new BigInteger("200");
System.out.println("加法\tb1.add(b2) = " + b1.add(b2));
System.out.println("减法\tb1.subtract(b2) = " + b1.subtract(b2));
System.out.println("乘法\tb1.multiply(b2) = " + b1.multiply(b2));
System.out.println("除法\tb1.divide(b2) = " + b1.divide(b2));
System.out.println("余数\tb1.remainder(b2) = " + b1.remainder(b2));
}
}
BigDecimal类
存储确切的小数
package com.sakura.api;
import java.math.BigDecimal;
import java.math.BigInteger;
public class Test1 {
public static void main(String[] args) {
BigDecimal bigDecimal = new BigDecimal("3.1415926");
System.out.println(bigDecimal);
BigDecimal b1 = new BigDecimal("10.00");
BigDecimal b2 = new BigDecimal("3.00");
System.out.println("加法\tb1.add(b2) = " + b1.add(b2));
System.out.println("减法\tb1.subtract(b2) = " + b1.subtract(b2));
System.out.println("乘法\tb1.multiply(b2) = " + b1.multiply(b2));
System.out.println("除法\tb1.divide(b2) = " + b1.divide(b2,20,BigDecimal.ROUND_FLOOR));
System.out.println("余数\tb1.remainder(b2) = " + b1.remainder(b2));
}
}
Random类
import java.util.Random;
public class Test1 {
public static void main(String[] args) {
Random random = new Random();
for (int i =0; i<5;i++){
System.out.print(random.nextInt(50)+"\t");
System.out.print(random.nextBoolean()+"\t");
System.out.print(random.nextDouble()+"\t");
System.out.println();
}
}
}
还可以设置种子:
import java.util.Random;
public class Test1 {
public static void main(String[] args) {
Random random = new Random(1); //此处设置种子为1
for (int i =0; i<10;i++){
System.out.println(random.nextInt(50)+"\t");
}
}
}
输出:
35
38
47
13
4
4
34
6
28
48
每次运行程序,输出的结果都一致
日期时间Api
已经过时的方法:
Calendar类
示例代码:
package com.sakura.api;
import java.util.Calendar;
public class Test1 {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
//System.out.println(calendar);
System.out.println("calendar.get(Calendar.YEAR) = " + calendar.get(Calendar.YEAR));
System.out.println("(calendar.get(Calendar.MONTH)+1) = " + (calendar.get(Calendar.MONTH) + 1));
System.out.println("calendar.get(Calendar.DATE) = " + calendar.get(Calendar.DATE));
System.out.println("calendar.get((Calendar.HOUR)) = " + calendar.get((Calendar.HOUR)));
/*修改日期
*属性: year,month,data...
* 值:正数 向后 负数 向前
* calender(属性,值);
* */
calendar.add(Calendar.YEAR,28);
System.out.println("calendar.get(Calendar.YEAR) = " + calendar.get(Calendar.YEAR));
calendar.add(Calendar.YEAR,20);
System.out.println("calendar.get(Calendar.YEAR) = " + calendar.get(Calendar.YEAR));
/*
设置时间
calender.set(year,month,data)
*/
calendar.set(2050,1,1,5,20);
System.out.println("calendar.get(Calendar.YEAR) = " + calendar.get(Calendar.YEAR));
System.out.println("calendar.get(Calendar.MONTH) = " + calendar.get(Calendar.MONTH));
}
}
输出:
calendar.get(Calendar.YEAR) = 2022
(calendar.get(Calendar.MONTH)+1) = 9
calendar.get(Calendar.DATE) = 15
calendar.get((Calendar.HOUR)) = 11
calendar.get(Calendar.YEAR) = 2050
calendar.get(Calendar.YEAR) = 2070
calendar.get(Calendar.YEAR) = 2050
calendar.get(Calendar.MONTH) = 1
获取时区
import java.util.TimeZone;
public class Test1 {
public static void main(String[] args) {
String[] availableIDs = TimeZone.getAvailableIDs();
for(String availableID : availableIDs){
System.out.println(availableID);
}
}
}
日期格式化
示例代码:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DataTest {
public static void main(String[] args) throws ParseException {
/*
日期转换:
*/
// 日期-->字符串
DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date1 = new Date();
System.out.println(date1);
String res1 = df1.format(date1);
System.out.println(res1);
// 字符串-->日期
DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String datastr = "2022-09-16 00:15:41"; //要解析的字符串内容必须与格式完全匹配,否则报错
Date date2 = df2.parse(datastr);
System.out.println(date2);
}
}
新增的三个日期对象
示例代码:
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
public class TestDate {
public static void main(String[] args) {
/*
LocalDate 年 月 日
不可变日期,一旦对日期做出修改会生成一个新的LocalDate记录改变后的日期
minusDays():日期减少
*/
//对 年 月 日 进行操作
LocalDate now = LocalDate.now();
System.out.println(now);
int year = now.getYear();
int month = now.getMonthValue();
int day = now .getDayOfMonth();
System.out.println("year = " + year);
System.out.println("month = " + month);
System.out.println("day = " + day);
System.out.println("-----------");
Month month1 = now.getMonth();
System.out.println("month1 = " + month1);
System.out.println(month1.getValue());
System.out.println("-----------");
LocalDate localDate = now.minusDays(15);
System.out.println("now = " + now);
System.out.println("localDate = " + localDate);
System.out.println("-----------");
LocalDate of = LocalDate.of(2050,12,31); //对年月日进行操作
System.out.println(of);
LocalDate localDate1 = of.plusDays(1);
System.out.println(localDate1);
System.out.println("-----------");
//对 时 分 秒 进行操作
LocalTime localTime = LocalTime.now();
System.out.println("localTime = " + localTime);//尾数是纳秒
System.out.println("-----------");
//同时对 年 月 日 时 分 秒 进行操作
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("localDateTime = " + localDateTime);
LocalDateTime of1 = LocalDateTime.of(2050,12,31,15,22);
System.out.println("of1 = " + of1);
}
}
输出:
2022-09-16
year = 2022
month = 9
day = 16
-----------
month1 = SEPTEMBER
9
-----------
now = 2022-09-16
localDate = 2022-09-01
-----------
2050-12-31
2051-01-01
-----------
localTime = 01:13:08.425
-----------
localDateTime = 2022-09-16T01:13:08.425
of1 = 2050-12-31T15:22
获取与指定时区时间和两个日期间隔
使用period计算时间间隔
示例代码:
import java.time.LocalDate;
import java.time.Period;
public class Test2 {
public static void main(String[] args) {
LocalDate l1 = LocalDate.now();
LocalDate l2 = LocalDate.of(2050,2,18);
System.out.println("l1 = " + l1);
System.out.println("l2 = " + l2);
Period period = Period.between(l1,l2);
System.out.println("period = " + period);
System.out.println("period.getYears() = " + period.getYears());
System.out.println("period.getMonths() = " + period.getMonths());
}
}
使用Duration计算两个时间间隔
示例代码:
import java.time.Duration;
import java.time.LocalDateTime;
public class Test2 {
public static void main(String[] args) {
LocalDateTime l1 = LocalDateTime.now();
LocalDateTime l2 = LocalDateTime.of(2050,12,31,15,21);
Duration duration = Duration.between(l1,l2); //计算两个时间的时间间隔
System.out.println("duration = " + duration);
System.out.println("duration.toDays() = " + duration.toDays());
System.out.println("duration.toHours() = " + duration.toHours());
}
}
DateTimeFormatter类:日期格式化类
示例代码:
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class Test2 {
public static void main(String[] args) {
LocalDateTime l1 = LocalDateTime.now();
System.out.println("l1 = " + l1);
/*
将日期转为字符串
*/
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE; // DateTimeFormatter 有提供好的模板,可以直接使用
String format = formatter.format(l1);
System.out.println("format = " + format);
//自定义格式
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss E");
String result = formatter1.format(l1);
System.out.println("result = " + result);
/*
将字符串转化为日期
*/
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss E");
String str = "2022-09-16 14:51:26 星期五";
LocalDateTime parse= LocalDateTime.parse(str,formatter2);
System.out.println("parse = " + parse);
}
}
系统相关类
import java.util.Properties;
public class SystemTest {
public static void main(String[] args) {
long l = System.currentTimeMillis(); //
System.out.println("l = " + l);
System.gc(); //运行垃圾回收器
int [] arr = {10,20,30};
int [] newArr = new int[arr.length];
System.arraycopy(arr,0,newArr,0,arr.length);
for (int i :newArr){
System.out.println(i);
}
System.out.println("-----------------");
Properties properties = System.getProperties();
// properties.list(System.out);
String property = System.getProperty("java.version");
System.out.println("property = " + property);
// Runtime
Runtime r1 = Runtime.getRuntime();
Runtime r2 = Runtime.getRuntime();
System.out.println(r1==r2); //说明了Runtime创建的对象都是同一个
System.out.println("r1.totalMemory() = " + r1.totalMemory()); //总内存
System.out.println("r1.freeMemory() = " + r1.freeMemory()); //剩余内存
}
}
数组的算法升华
数组的反转
方法一 创建一个新数组
public class ArrayTest {
public static void main(String[] args) {
int [] arr = {10,20,30,40,50,60,70};
//交换方法一 创建一个新数组
int [] newarr = new int[arr.length];
int index = 0;
for (int i =arr.length-1;i>=0;i--){
newarr[index++] = arr[i];
}
for (int i : newarr) {
System.out.println(i);
}
}
}
方法二数组内交换
public class ArrayTest {
public static void main(String[] args) {
int [] arr = {10,20,30,40,50,60,70};
//交换方法二 数组内交换
for (int i =0;i<arr.length/2;i++){
int temp;
temp = arr[i];
arr[i] = arr[arr.length-1-i];
arr[arr.length-1-i] = temp;
}
for (int i : arr) {
System.out.println(i);
}
}
}
数组的二分查找
public class ArrayTest {
public static void main(String[] args) {
int[] arr = {10, 20, 30, 40, 50, 60, 70,82,92,103};
//二分查找。二分查找排序必须是有序的
int res = binarySearch(arr,103);
System.out.println("您要查找的数字下标为"+res);
}
private static int binarySearch(int[] arr, int ele) {
int ArrIndex = 0;
int ArrEnd = arr.length - 1;
while (ArrIndex <= ArrEnd) {
int ArrMid = (ArrIndex + ArrEnd) / 2;
if (ele > arr[ArrMid]) {
ArrIndex = ArrMid + 1;
} else if (ele < arr[ArrEnd]){
ArrEnd = ArrMid;
} else {
return ArrMid;
}
}
return -1;
}
}
day17
数组的扩容
示例代码:
public class ArrTest {
@Test
public void test01(){
//旧数组不够要扩容
String [] strarr = {"张三","李四","王五"};
//现在有需求,需要将数组扩容至原来的两倍、
String [] newarr = new String[strarr.length*2];
//先将旧数组复制到新数组
System.arraycopy(strarr,0,newarr,0,3);
//添加需要的值
newarr[strarr.length] = "李白";
newarr[strarr.length+1] = "杜甫";
newarr[strarr.length+2] = "白居易";
//将新数组的地址赋值给旧数组
strarr = newarr;
//输出旧数组
for (String s : strarr) {
System.out.println(s);
}
}
}
数组的插入
数组未满
示例代码:
@Test
public void test02(){
//数组的插入,分两种情况,数组未满和数组已满
//1.数组未满
String [] arr = new String[5];
arr[0] = "蔡徐坤";
arr[1] = "肖战";
arr[2] = "王一博";
System.arraycopy(arr,1,arr,2,2); //从第二个元素开始,整体后移一个位置
arr[1] = "赵四"; //在第二个位置插入赵四
for (String s : arr) {
System.out.println(s);
}
}
数组已满
示例代码:
@Test
public void test03(){
//数组已满的时候插入元素
String [] arr = {"张三","李四","王五"};
//需求:在张三和李四中间插入一个蔡徐坤
//由于数组已满,所以我们需要进行扩容,并将改变之前的赋值给新数组
String [] newarr = new String[arr.length+1]; //扩容操作
int index = 1;
for (int i =0;i<index;i++){
newarr[i] = arr[i];
}
System.arraycopy(arr,1,newarr,2,2);
newarr[1] = "蔡徐坤";
arr = newarr;
for (String s : arr) {
System.out.println(s);
}
}
数组的删除
思路一:
新建一个数组
@Test
public void test04(){
String [] arr = {"张三","李四","王五"};
//新建一个数组
String [] newarr = new String[arr.length-1];
newarr[0] = arr[0];
newarr[1] = arr[2];
arr = newarr;
for (String s : arr) {
System.out.println(s);
}
}
思路二:
在数组内进行操作
@Test
public void test05(){
String [] arr = {"张三","李四","王五"};
//数组内进行操作
System.arraycopy(arr,2,arr,1,1);
arr[2] = null;
for (String s : arr) {
System.out.println(s);
}
}
选择排序
示例代码:
@Test
public void test06(){
int [] arr = {100,50,90,45,56,73,20};
for (int i =0;i<arr.length-1;i++){
int minindex = i;
for (int j=i+1;j<=arr.length-1;j++){
if (arr[minindex] <= arr[j]){
continue;
}else {
minindex = j;
}
}
int temp = arr[i];
arr[i] = arr[minindex];
arr[minindex] = temp;
}
for (int i : arr) {
System.out.println(i);
}
}
数组的工具类
Arrays.toString函数
@Test
public void test11(){
int [] arr = {10,20,50,32,12};
System.out.println(arr);
System.out.println(Arrays.toString(arr));
}
输出数组的值
Arrays.deepToString函数
Array.toString函数只能显示一维数组
@Test
public void test11(){
int [] [] arrs = {{1,2},{22,43},{97,67}};
System.out.println(Arrays.toString(arrs));
System.out.println(Arrays.deepToString(arrs));
}
Arrays.sort方法
@Test
public void test07(){
//Array.sort可以对数组进行排序
int [] arr = {50,56,12,80,5};
System.out.println(Arrays.toString(arr));
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
问题:如何对对象数组进行比较?
如果我们直接进行排序就会报错,因为程序不知道根据什么进行比较
解决方法:重写Comparable
方法一:继承的方式
示例代码:
public void test08(){
Person p1 = new Person("David",17);
Person p2 = new Person("瑞贝卡",15);
Person p3 = new Person("Lucy",19);
Person [] arr = {p1,p2,p3};
System.out.println(Arrays.toString(arr));
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
class Person implements Comparable{
@Override
public int compareTo(Object o) {
Person p = (Person)o;
return this.age-p.age;
}
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
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 +
'}';
}
}
方法二:采用匿名内部类
@Test
public void test09(){
Person p1 = new Person("David",17);
Person p2 = new Person("瑞贝卡",15);
Person p3 = new Person("Lucy",19);
Person [] arr = {p1,p2,p3};
System.out.println(Arrays.toString(arr));
Arrays.sort(arr, new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
Person p1 = (Person) o1;
Person p2 = (Person) o2;
return p1.getAge()-p2.getAge();
}
});
System.out.println(Arrays.toString(arr));
}
class Person{
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person() {
}
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 +
'}';
}
}
Arrays.fill函数
注意:此函数范围为左闭右开
[n,m)
@Test
public void test10(){
int [] arr = {10,20,50,32,12};
System.out.println(Arrays.toString(arr));
Arrays.fill(arr,0,2,666); //注意:此函数范围是左闭右开
System.out.println(Arrays.toString(arr));
}
Arrays.equals函数
比较的是内容及其下标是否完全一致
@Test
public void test12(){
int [] arr1 = {10,20,50,32,12};
int [] arr2 = {10,20,50,32,12};
System.out.println(arr1==arr2);
boolean flag = Arrays.equals(arr1,arr2);
System.out.println("flag = " + flag);
}
Arrays.copyOf函数
复制旧数组,创建一个新数组
@Test
public void test13(){
int [] arr1 = {10,20,50,32,12};
int [] arr2 = Arrays.copyOf(arr1,2);
System.out.println(Arrays.toString(arr2));
}
Arrays.copyOfRange函数
复制旧数组的一段,创建一个新数组
范围也是左闭右开
[n,m)
@Test
public void test13(){
int [] arr1 = {10,20,50,32,12};
int [] arr2 = Arrays.copyOfRange(arr1,2,4);
System.out.println(Arrays.toString(arr2));
}
字符串的简介介绍
创建字符串的方式
public class TestSrting {
public static void main(String[] args) {
//方式一
String s1 = "你好";
//方式二
char [] a = {'a','b'};
String s2 = new String(a);
System.out.println(s2);
//方式三
String s3 = new String("世界");
//方式四
byte [] bytes = {65,66,67,97};
String s4 = new String(bytes); //会将byte类型中的数字解析为对应字符
System.out.println(s4);
String s5 = new String(bytes,1,2); //从1开始,取两个
System.out.println(s5);
//方式五 通过方法创建
char [] c = {'a','b','c'};
int b = 5;
String s6 = ""+b; //字符串与整数相连接成为字符串
String s7 = String.valueOf(b); //方法返回值为字符串
String s8 = String.copyValueOf(c,0,3);
//方法有很多,多翻阅文档
}
}
对象的个数问题
public class TestSrting {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "hello";
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
}
}
public class TestSrting {
public static void main(String[] args) {
String s1 = "hello";
String s2 = new String("hello");
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
}
}
String内存分析
字符串的拼接
jdk7以后,调用intern方法时,如果该字符串已经存在于常量池中,则将常量池中的引用直接返回;如果不存在,则在常量池中生成一个对原字符串的引用。
字符串常用方法一
字符串常用方法二
public class TestSrting {
public static void main(String[] args) {
String message = "hello word!";
//contain 判断是否包含指定字符串
boolean flag1 = message.contains("he");
boolean flag2 = message.contains("he11");
System.out.println("flag1 = " + flag1);
System.out.println("flag2 = " + flag2);
//indexOf 查找指定元素第一次出现得下标,从0开始 不存在返回-1
int res1 = message.indexOf("l");
int res2 = message.indexOf("o");
System.out.println("res1 = " + res1);
System.out.println("res2 = " + res2);
//lastIndexOf 查找指定元素最后一次出现的位置 不存在返回-1
int res3 = message.lastIndexOf("l");
System.out.println("res3 = " + res3);
//截取字符串
String s1 = message.substring(6); //从第六个字符开始截取,包括第六个字符
System.out.println("s1 = " + s1);
String s2 = message.substring(0,5); //截取第1个道第五个字符,左闭右开
System.out.println("s2 = " + s2);
//获取指定位置字符串
char c =message.charAt(message.length()-1);
System.out.println("c = " + c);
//将字符串转化为char数组
char [] chars = message.toCharArray();
System.out.println(Arrays.toString(chars));
}
}
字符串常用方法三
public class TestString2 {
public static void main(String[] args) throws UnsupportedEncodingException {
String message = "你好世界";
byte [] bytes = message.getBytes();
System.out.println("Arrays.toString(bytes) = " + Arrays.toString(bytes));
byte [] messBytes = message.getBytes("iso8859-1"); //这是统一标准
System.out.println(Arrays.toString(messBytes));
System.out.println(message.getBytes("gbk").length); //国标 一个汉字等于两个字节
System.out.println(message.getBytes("utf-8").length); //一个汉字等于三个字节
}
}
starts with和ends with、正则表达式、replace函数、split函数
public class TestString2 {
public static void main(String[] args) throws UnsupportedEncodingException {
//判断以什么开头和以什么结尾
String message = "I really want to stat at your house";
boolean flag1 = message.startsWith("I");
System.out.println("flag1 = " + flag1);
boolean flag2 = message.endsWith("house");
System.out.println("flag2 = " + flag2);
//replace函数,替换第一个字符
String rpmessage = message.replace("stat at your house","love you");
System.out.println("rpmessage = " + rpmessage);
//replaceall函数,替换所有字符,第一个参数可用正则进行匹配
String message2 = "wo wo wo love you";
String rpmessage2 = message2.replaceAll("wo","I");
System.out.println("rpmessage2 = " + rpmessage2);
//split函数分割字符串 可用正则匹配
String s1 = "Fly1to1the1moon";
String [] strings = s1.split("1");
System.out.println(Arrays.toString(strings));
//正则表达式进行匹配
/*
[]:代表一个字符
[a-z]:小写字母[a-z]任何一个都可以
+: 一个或多个
*: 0个或多个
[^a]:代表匹配不是a的数据
^ :代表以什么开始
$ : 代表以什么结尾
\d:代表任意一个数字 0-9
\w 代表数字字母和下划线
*/
String s2 = "b";
boolean matchs = s2.matches("[^a]");
System.out.println("matchs = " + matchs);
}
}
day18
StringBuilder与StringBuffer
StringBuffer常用方法
版权声明:本博客所有文章除特殊声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明出处 sakura的博客!