目录
java面试题:为什么String不可变、StringBuffer/StringBuilder可变
vector集合和(非线程安全)ArrayList集合转换成线程安全
DataOutputStream和DataInputStream
ObjectInputStream 和ObjectOutputStream
线程生命周期获取编辑取当前线程对象、对象名字、修改线程名字
sleep()方法、interrupt()方法、更好的线程终止方法
StringBuilder的用法
String number="1234";
StringBuilder sb=new StringBuilder(number);
sb.append(56);
System.out.println(sb); //123456
System.out.println(sb.toString()); //1234456 一般与return使用
sb.insert(6,7);
System.out.println(sb); //1234567 位置
sb.deleteCharAt(6); //123456 下标
System.out.println(sb);
sb.delete(1,2); //下标,左闭右开
System.out.println(sb); //13456
System.out.println(sb.reverse()); //65431
数组排序后输出原数组下标
import java.util.Arrays;
import java.util.Comparator;
class hh{
public static void main(String[] args) {
Integer []arr={1,5,7,4,6,9};
Integer []arr1=new Integer[arr.length];
for(int i=0;i<arr.length;i++)
arr1[i]=i;
System.out.println("数组元素");
System.out.println(Arrays.toString(arr));
System.out.println("排序前数组元素下标");
Arrays.sort(arr1, Comparator.comparingInt(i->arr[i]));
System.out.println(Arrays.toString(arr1));
System.out.println("排序后数组元素");
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
字符串排序
class hh{
public static void main(String[] args) {
String arr="cba";
char []arr1=arr.toCharArray();
Arrays.sort(arr1);
System.out.println(arr1);
}
}
对日期处理
Date date=new Date();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:sss");
System.out.println(sdf.format(date));
staict用法
extends用法
int 、 String、 Integer 之间转换
//int ->String
int i=1;
String j=String.valueOf(i);
//或者
String k=i+"";
//String -> int
String n="123";
int m=Integer.parseInt(n);
//int ->Integer
int q=1;
Integer in=q;
//或者直接转,系统自动装箱
Integer ine=1;
//Integer -> int
Integer w=1;
int e=w;
//或者直接转,系统自动拆箱
int r=1;
//String -> Integer
String a="ad";
Integer s=Integer.valueOf(a);
//Integer ->String
Integer x=1;
String c=String.valueOf(x);
java面试题:为什么String不可变、StringBuffer/StringBuilder可变
我看过源代码,String类中有一个bety[ ]数组,这个bety[ ]数组采用了final修饰,因为数组一旦创建长度不可变。并且被final修饰的的引用对象一但指向某个对象之后,不可再指向其他对象,所以String是不可变的!
我看过源代码,StringBuffer/StringBuilder内部实际上是一个bety[ ]数组,这个bety[ ]数组没有被final修饰,StringBuffer/StringBuilder的初始化容量我记得大致是16,当存满之后会进行扩容,底层采用了数组拷贝的方法System.arraycopy()...是这样扩容的。所以StringBuffer/StringBuilder适合字符串频繁拼接
统计一个方法的耗费时长(毫秒)
long begin=System.currentTimeMillis();
for(int i=0;i<1000;i++){
System.out.println(i);
}
long end=System.currentTimeMillis();
System.out.println(end-begin);
数字格式化
//#代表任意数字
//,代表千分位
//.代表小数点后几位
//0代表不够不零
DecimalFormat df=new DecimalFormat("###,###.0000");
System.out.println(df.format(1234.567));
高精度的BigDecimal
//1.BigDecimal属于大数据,精度极高,不属于基本数据类型,属于java对象(引用数据类型)是
//SUN公司提供的一个类。专门在财务软件中
//2.注意财务中double是不够的,当面试的时候经理问你处理财务数据吗,用的是那种类型
//不要说是double,说java.math.BigDecimal
BigDecimal v1=new BigDecimal(100);
BigDecimal v2=new BigDecimal(200);
BigDecimal v3=v1.add(v2); //不能用+-*/应该用math里面的方法
System.out.println(v3);
生成随机数
Random rd=new Random();
//产生一个int类型的随机数
int num=rd.nextInt();
System.out.println(num);
//产生一个有范围的随机数,nextInt翻译为:下一个int类型的数据,表示只能取到100
int num2= rd.nextInt(1001);
System.out.println(num2);
二分查找
int []arr={1,5,2,3,9};
Arrays.sort(arr);
int num1=Arrays.binarySearch(arr,5); //找到返回大于0
int num2=Arrays.binarySearch(arr,7); //没找到返回小于0
System.out.println(num1);
System.out.println(num2);
try{}catch(){}异常处理机制运行步骤
//防止当出现异常代码不能运行
try{
int i=10/0; //当出现异常直接进入catch语句
System.out.println(i);
}catch (Exception e){
System.out.println("输入不合法");
}
枚举与switch连用
public class main {
public static void main(String[] args) {
switch (Season.SPRING){
case SPRING -> System.out.println("春天");
case SUMMER -> System.out.println("夏天");
case AUTUMN -> System.out.println("秋天");
case WINTER -> System.out.println("冬天");
}
}
}
enum Season{
SPRING,SUMMER,AUTUMN,WINTER
}
方法重载
public class Test {
public static void main(String[] args) {
//方法重载
//缺点:功能“相似”,作用“相似”,代码不美观
System.out.println(add(1,2));
System.out.println(add(1.0,2.1));
System.out.println(add(1.1,2.2));
}
public static int add(int i,int j){
return i+j;
}
public static double add(double i,double j){
return i+j;
}
public static float add(float i,float j){
return i+j;
}
}
构造方法
public class ConstructorMethod {
//一个类如果没有构造方法,那么会有一个默认的无参构造方法
//构造方法的作用是个实例变量(全局变量)初始化
int i;
ConstructorMethod(){
}
ConstructorMethod(int i){
this.i=i;
}
}
封装
public class Encapsulation {
//封装的两个作用
//保证内部结构安全
//屏蔽复杂,暴露简单
//一个类体当中的数据,在封装之后,对于代码调用人员来说
//不需要关心代码的复杂实现,只需要通过一个简单的入口就可以访问
//另外类体安全的级别高的数据封装起来,外部人员不能随意访问
//来保证数据的安全
public static void main(String[] args) {
Data d=new Data();
System.out.println(d.getData());
d.setData(3);
}
}
class Data{
int data;
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
}
static
//static翻译为“静态” //所有static修饰的关键字都是类相关的,类级别的 //所有static修饰的,采用“类名.”访问 //static修饰的变量:静态变量 ,静态变量储存在方法区中 //static修饰的方法:静态方法 ,里面不能用静态变量 //非static修饰的方法:实例方法 ,里面不能用静态变量 //方法体外变量:成员变量 //方法体中变量:局部变量 ,里面不能用静态变量 ,储存栈中 //成员变量可以分: //实例变量:储存在堆中 //静态变量:储存方法区 //静态代码块 //一个类可以多个静态代码块 //静态代码块在类加载时候执行 //静态代码块自上而下执行 //静态代码块只执行一次
带static与不带static方法区别
public class Mothod {
public static void main(String[] args) {
M.doSome(); //带static方法,通过类名.调用。
//若通过对象.调用在运行阶段JVM会自动转换成类名.调用
M m=new M();//不带static方法,通过对象.调用
m.doOther();
}
}
class M{
public static void doSome(){
System.out.println("带static的方法");
}
public void doOther(){
System.out.println("不带static的方法");
}
}
静态代码块
//静态代码块
//一个类可以多个静态代码块
//静态代码块在类加载时候执行
//静态代码块自上而下执行
//静态代码块只执行一次
static {
System.out.println("A");
}
static {
System.out.println("B");
}
public static void main(String[] args) {
System.out.println("主函数执行了"); //ABC主函数执行了
}
static {
System.out.println("C");
}
}
实例代码块
public class Test {
//实例代码块
//在new对象之前执行
//每new一次对象执行一次
public static void main(String[] args) {
System.out.println("main 函数执行");
new S();
new S(1);
//结果:main 函数执行
//实例代码块执行
//无参构造函数执行
//实例代码块执行
//有参构造函数执行
}
}
class S{
{
System.out.println("实例代码块执行");
}
int i;
S(){
System.out.println("无参构造函数执行");
}
S(int i){
System.out.println("有参构造函数执行");
}
}
this
//this表示当前对象 ,一个对象一份,存在对象里面 //this是关键字 //this是变量 //this 是个引用,保存当前对象内存地址 //this 存在堆内存 //this 只使用实例方法中和构造方法
extends(继承)
public class Static {
//继承 extends
//子类继承父类,除构造方法和private修饰的数据外,其他都可以继承
//若类没被继承,默认Object
//继承的缺点:耦合度高,父类修改,子类受到牵连
public static void main(String[] args) {
Cat cat=new Cat();
cat.doSome(); //动物
}
}
class Animal{
public void doSome(){
System.out.println("动物");
}
}
class Cat extends Animal{
}
重写(方法覆盖)
public class Static {
//重写(方法覆盖)
//父类无法满足子类需求
//重写的条件
//继承关系
//相同方法名、返回类型、参数列表
//访问权限不能低,只能更高
//子类的重写的方法抛出异常不能多于父类
//方法重写注意事项
//方法覆盖只针对方法,和属性无关
//私有方法无法覆盖
//方法覆盖只针对‘实例方法’,静态方法没有意义
//重写与重载有区别
//重载是单独类中
//重写是在继承中
public static void main(String[] args) {
Cat cat=new Cat();
cat.doSome(); //猫
}
}
class Animal{
public void doSome(){
System.out.println("动物");
}
}
class Cat extends Animal{
public void doSome(){
System.out.println("猫");
}
}
多态、instanceof、super
public class Static {
//多态
//也称上转型
//多态指的是父类型引用指向子类型对象
//编译阶段绑定父类行方法、
//运行阶段动态绑定子类型对象方法
public static void main(String[] args) {
Animal cat=new Cat();
cat.doSome(); //猫
//分析cat.doSome()
//java程序分为编译阶段和运行阶段
//先编译阶段:
//对于编译器来说,编译器只知道cat是Animal类型
//所以编译器在检查语法的时候,会去Animal.class字节码中找到doSome()方法
//找到了,绑定doSome()方法,静态绑定成功(编译阶段属于静态绑定)
//然后进入运行阶段:
//在运行阶段的时候,实际上java在堆内存中创建的是Cat的对象
//所以doSome的时候,真正参与doSome的对象是猫,
//运行阶段则会执行Cat对象的doSome的方法(运行阶段属于动态绑定)
((Cat)cat).mySome(); //结果是:鸟子类特有的方法 调用子类特有的方法需要强制类型转换、也称下转型
//instanceof运算符
//在强制类型转换时候,为了避免转换类型与对象类型不一致
//运算的结果为true/false
if (cat instanceof Cat){
((Cat)cat).mySome(); //虽然看的很鸡肋,但子类多了就不一样
}
//super:
//要想多态必须继承,那么问题来了
//继承的时候构造方法无法继承
//这个时候super来了
//super能出现在实例方法和构造方法中
//语法是super.和super()
//super不能使用在静态方法中
//super()只能出现在构造方法第一行,通过当前的构造方法调用父类中构造方法(目的是代码复用)
//当子类构造方法没有使用super(),系统自动加super()调用父类无参构造方法
//super.可以访问父类方法也可以访问父
//super 不是引用,也不保存地址,也不指向对象类属性
//super 只是代表当前对象内部的那一块父类型特征
}
}
class Animal{
int i;
Animal(){
}
Animal(int i){
this.i=i;
}
public void doSome(){
System.out.println("动物");
}
}
class Cat extends Animal{
int i;
int j;
Cat(){
}
Cat(int i,int j){
super(i);
this.j=j;
}
public void doSome(){
System.out.println(i); //子类的值
System.out.println(this.i); //子类的值
System.out.println(super.i); //父类的值
System.out.println("猫");
super.doSome();
}
public void mySome(){
System.out.println("猫子类特有的方法");
}
}
final、finally、finalize区别
//final //final修饰的类无法继承 //final修饰的方法无法覆盖 //final修饰的变量不能重新赋值 //finally //和try一起联合sy //finally语句块里面是一定执行的 //finalize //是Object类中的方法名 //这个防范由垃圾回收器调用
抽象类、抽象方法
public class Abstract {
/*
* 抽象类
* 类与类具有共同特征,将这些共同特征提取出来,形成的就是抽象类
* 抽象类是引用数据类型
* 抽象类本身是不存在的,无法创建对象,(无法实例化)
* 抽象类可以被继承,子类是可以实例化,子类一定要实现抽象方法,(继承了,
* 相当于把父类方法复制一份到子类中
* 但是由于抽象方法必须要出现在抽象类中)
* 抽象类可以有构造方法
* 抽象类一般与继承关联,
* 抽象类中不一定要有抽象方法
* 抽象类中可以有非抽象方法
* 抽象方法一定要在抽象类中
* */
public static void main(String[] args) {
A c=new B(); //这就是面向抽象编程
c.a();
}
}
abstract class A{
int i;
A(){
}
A (int i){
this.i=i;
}
public abstract void a(); //抽象方法
public void b(){
System.out.println("hh");
}
}
class B extends A{
@Override
public void a() { //实现抽象方法,也可以将B类继续抽象就可以不用实现
System.out.println("w");
}
}
接口
public class Interface {
/*
* 接口也是一种数据类型
* 接口是完全抽象的,(抽象类是半抽象的)
* 接口支持多继承
* 接口只包括两个内容,常量和抽象方法(接口中只要定义变量就自动转换常量)
* */
public static void main(String[] args) {
}
}
interface A{ //定义接口
}
interface B extends A{
}
interface C extends A,B{
public static final double PI=3.14;
int i=19;
//public abstract int a();
int a(); //两个都可以
}
class hh implements C ,A{
public int a(){ //这里的public不能省,因为默认的比这个低
System.out.println("ddd"); //实现接口
return 0;
}
}
java三大特性关系
基本类型和包装类型的区别
1.包装类型可以为null,基本类型不行(数据库中若用基本类型会空指针异常)
2.包装类型可以用泛型
3.两个包装类型值可以相等,当不相等(当在100以内是相等的,java有什么机制)
4.自动拆箱装箱
集合的概念
什么是集合、集合有什么用? 数组就是集合,集合是个容器,可以容纳其他类型数据 集合为什么说在开发中使用较多? 集合是一个容器,是一个载体,可以一次容纳多个对象, 在实际开发中,假设连接数据库,数据库当中有10条记录, 那么假设把这都查询出来,在java中会有10条数据封装成10个对象 然后把封装成的10个java对象放到某一个集合当中,将集合传到前端,然后 遍历集合,将数据一个一个展现出来 集合不能直接储存基本数据类型,集合不能直接储存java对象 集合储存的都是java对象内存地址或者说是引用 在java中每个不同的集合,对应不同的数据结构,往不同的集合中储存元素,等于将数据放的不同的数据结构中 集合在java.util.*包下
集合继承结构图
Collection接口中常用的方法
/*
* Collection接口中常用的方法
*
* Collection中能放什么元素?
* 没有使用“泛型”可以使用Object子类中所有的方法
*
* Collection中常用的方法
*
* boolean add(Object) //向集合中添加个数
* int size() //获取集合中个数
* void clear() //清空集合
* boolean contains(Object o) //判断集合中是否有元素o ,包含返回ture 不false
* boolean remove(Object o) //删除o元素
* boolean isEmpty //判断集合是否为空
*Object[] toArray() //将集合转换数组
*
* */
public static void main(String[] args) {
Collection c=new ArrayList();
c.add(1200);//自动装箱,实际上是放进去一个对象内存地址。Integer x=new Integer();
c.add(new Object());
c.add(true);
c.add(new Student());
//获取集合中元素个数
System.out.println("集合中元素个数"+c.size());
//清空集合
c.clear();
System.out.println("集合中元素个数"+c.size());
//添加元素
c.add("qq");
c.add("aer");
c.add("周添加");
//判断集合是否包含某个元素
boolean f=c.contains("周添加");
System.out.println(f);
//删除o元素
c.remove("周添加");
//判断集合是否为空
System.out.println(c.isEmpty());
//将集合转换数组
Object[] objects=c.toArray();
for (int i=0;i<objects.length;i++){
System.out.println(objects[i]);
}
}
}
class Student{
}
Collection接口中contains方法详解
public class CollectionTest3 {
public static void main(String[] args) {
Collection c = new ArrayList();
User user1 = new User("jake");
User user2 = new User("jake");
c.add(user1);
System.out.println(c.contains(user1));
System.out.println(c.contains(user2)); //底层调用equals方法比较
System.out.println(user1.equals(user2));
}
}
class User{
private String name;
public User() {
}
public User(String name) {
this.name = name;
}
// @Override
// public boolean equals(Object o) {
// if (o==null||!(o instanceof User)) return false;
// if(o==this) return true;
// User u=(User) o;
// return u.name==this.name;
// }
}
关于集合迭代、遍历
public class CollectionTest2 {
/*
* 关于集合迭代、遍历
* 下面的遍历、迭代是所有Collection通用的方式
* 在Map集合不能使用
* 在所有Collection子类使用
* */
public static void main(String[] args) {
Collection c=new ArrayList(); //后面无所谓,重要看Collection接口怎么迭代、遍历
c.add("asd0");
c.add(100);
c.add(new Object());
//对集合迭代、遍历
//第一步,获取集合中迭代器对象Iterator
Iterator i=c.iterator();
//第二步,通过以上迭代器对象进行迭代、遍历
//下面两个方法是迭代器Iterator中的方法
//boolean hasNext()如果“仍”有元素可以迭代,返回ture,(开始指向-1,集合下标从0开始)
//Object next()返回迭代的下一个元素
// for (int j=0;j<c.size();j++){
// if (i.hasNext()){
// System.out.println(i.next());
// }
// }
//可以这样写
while (i.hasNext()){
Object o= i.next(); //迭代器返回的是Object类型,不能用其他类型接收
//c.remove(100);
//上面一行代码会出现问题
// Exception in thread "main" java.util.ConcurrentModificationException
// at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
// at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
// at Test.CollectionTest2.main(CollectionTest2.java:38)
//迭代器获取了元素转换,若改边了集合中的结构则会出现异常
//使用迭代器中的remove方法可以同时删除迭代器和集合的元素,这个是删除大当前指向的元素
i.remove();
System.out.println(o);
//System.out.println(i.next());
}
}
}
面试题:集合当中你用的那个集合最多
答:ArrayList集合,向数组末尾添加元素效率不受影响
另外数组检索、查找比较多,效率高(每个元素占用可以大小一样,内存地址连续,通过数学表达式算出内存地址)
List接口储存元素方法和ArrayList集合使用
public class ListText
{
/*
* List接口储存元素方法的特点:
* 有序(有下标),可重复
*
* List接口既然是Collection接口的子接口,那么肯定有自己特有的方法
*void add(int index,Object o) 用下标添加元素
* int indexOf(Object o) 判断元素第一次出现的下标,存在返回下标,不存在返回-1
* * Object get(int index) 根据下标获取元素
* int lastIndexOf(Object o) 判断元素最后一次出现的下标,存在返回下标,不存在返回-1
* Object remove(int index) 删除
* Object set(int index,Object element) 改
*
*
* ArrayList集合初始化容量是10(底层先创建长度是0的数组,当添加第一个元素的时候,初始化容量是10)
* ArrayList底层是调用Object[]数组
*ArrayList扩容是1.5倍
*ArrayList是非线程安全的
* */
public static void main(String[] args) {
List i =new ArrayList();
List k=new ArrayList(20);
i.add("sd");
i.add("we");
i.add("df");
Collection v=new HashSet();
v.add(1);
v.add(2);
v.add(3);
List l=new ArrayList(v); //通过这个构造方法可以将HashSet集合转换成ArrayList集合
//添加元素,并不会将下标二的元素覆盖只是将下标2的元素后移
i.add(2,"ll");
Iterator c=i.iterator();
while (c.hasNext()){
System.out.println(c.next());
}
System.out.println("------------");
System.out.println(i.get(0));
//可以通过这个遍历集合
for (int j=0;j<i.size();j++){
System.out.println(i.get(j));
}
System.out.println(i.indexOf("sd1"));
}
}
LinkedList集合的使用
public class LinkedListTest {
/*
* 链表优点
* 元素地址不连续,随机删除某个元素不会出现大量元素位移
*
* 缺点
* 不能通过数学表达式计算元素地址,每次查找都需要遍历
* * */
public static void main(String[] args) {
List l=new LinkedList();
l.add(1);
l.add(2);
l.add(3);
//注意LinkList也有下标,
//ArrayList检索效率高不单单是下标,底层是数组,内存地址连续,可以通过数学表达式计算元素地址
for (int i=0;i<l.size();i++){
System.out.println(l.get(i));
}
}
}
vector集合和(非线程安全)ArrayList集合转换成线程安全
/*vector集合
* 底层也是一个数组
* 初始容量是10
* 扩容是2倍
*Vector中所有的方法都是线程同步的,都带有synchronized关键字,是线程安全的
* 效率较低,使用较少
*
*
* 怎么将将ArrayList集合转换成线程安全
* 使用集合工具类:
* java.util.Collections;
* java.util.Collections; //是集合工具类
* java.util.Collection; // 集合接口
*
*
* */
public static void main(String[] args) {
List v=new Vector();
v.add(1);
v.add(1);
v.add(1);
v.add(1);
v.add(1);
Iterator i=v.iterator();
while(i.hasNext()){
System.out.println(i.next());
}
List z=new LinkedList(); //非线程安全
z.add(1);
z.add(1);
Collections.synchronizedList(z); //线程安全了
}
}
泛型的理解与 使用
/*
* 泛型
* jdk5之后退出特性
* 只在编译阶段起作用,只是给编译器参考的(运行阶段不起作用)
*
* 好处
* 类型统一
* 不需要大量强制类型转换(父类不用转型,子类还是需要转型的)
*
* 缺点
* 元素多样形少
*
*
* jdk8之后引入:自动类型表达式(又称钻石表达式)
*
* */
public class GenericTest {
public static void main(String[] args) {
//没有使用泛型
All a=new Bll();
All b=new Cll();
List list=new LinkedList();
list.add(a);
list.add(b);
Iterator iterator=list.iterator();
while (iterator.hasNext()){
Object o=iterator.next();
if (o instanceof Bll){
((Bll) o).m();
}
if (o instanceof Cll){
((Cll) o).k();
}
}
//使用泛型
//指定这个集合只能储存All,当然我Bll和Cll继承了也可以使用
All a1=new Bll();
All b1=new Cll();
List<All> list1=new LinkedList<All>();
// List<All> list1=new LinkedList<>(); //LinkedList<All>中的All可以不写,jdk可以自动推断
list1.add(a1);
list1.add(b1);
//list1.add(1); //这个就不行了
Iterator<All> iterator1=list1.listIterator();
while (iterator1.hasNext()){
Object o1=iterator1.next();
if (o1 instanceof Bll){
((Bll) o1).m();
((Bll) o1).move1();
}
if (o1 instanceof Cll){
((Cll) o1).k();
}
}
}
}
class All{
public void move1(){
System.out.println("hh");
}
}
class Bll extends All{
public void m(){
System.out.println("jj");
}
}
class Cll extends All{
public void k(){
System.out.println("rr");
}
}
自定义泛型
/*自定义泛型
* <> 里面可以随便写,标识符
* java源代码中的<E>、<T>
E是Element
* T是Type
* */
public class GenericTest {
public static void main(String[] args) {
A<String> i=new A<>(); //<> 里面可以随便写,标识符
i.get();
//int j=i.get(); //类型不匹配,指定的是String类型
}
}
class A<T>{
public T get(){
return null;
}
}
增强for循环
public class ForEachTest {
public static void main(String[] args) {
int []a={1,2,34,5,6};
for (int i=0;i<a.length;i++){
System.out.println(a[i]);
}
//增强for循环
//for(元素类型 变量名:数组或集合){}
for (int data:a
) {
//data代表数组中的元素(foreach循环的缺点:没有下标)
System.out.println(data);
}
List<String> list=new LinkedList<>();
list.add("dsa");
list.add("ewr");
for (String s:list
) {
System.out.println(s); //可以不用使用迭代器
}
}
}
HashSet集合
/*
* HashSet集合
*无序不重复
* 储存的循序与取出的循序不同
* 放到HashSet集合的元素实际上放到了HashMap集合的Key部分去了
* */
public static void main(String[] args) {
Set<String> s=new HashSet<>();
s.add("ds");
s.add("eqw");
s.add("gf");
s.add("gf");
for (String s1:s
) {
System.out.println(s1);
}
}
}
TreeSet集合
/*
* TreeSet集合
*
* 无序不可重复
* 但是储存的元素自动排序
*
* */
public static void main(String[] args) {
Set<Integer> i=new TreeSet<>();
i.add(2);
i.add(4);
i.add(1);
i.add(3);
for (Integer i1:i
) {
System.out.println(i1); //1,2,3,4
}
}
}
Map接口常用的方法和遍历Map集合
public class MapTest {
/*
* Map接口常用的方法
* Map和Collection没有继承关系
* Map集合以key和value方式储存:键值对
* key 和value都是引用数据类型
* key和value都是对象内存地址
* key 起主导作用,value是key的附属品
*
* Map接口常用的方法:
* V put(K key, V Value)向Map集合添加键值对
* V get(Object key)通过key获取value
* void clear()清空Map集合
* boolean containsKey(Object key)判断Map中是否包含value
* boolean isEmpty() 判断Map集合是否为0;
* Set<K> keySet()获取Map集合所有key(所有的键是一个Set集合)
* V remove(Object key)通过key删除键值对
* int size()获取Map集合键值对的个数
* Collection<V> values() 获取Map集合所有的value 返回一个Collection集合
* Set<Map.Entry<K,V>> entrySet() 将Map集合转换Set集合
* 解释:
* map1集合对象
* key value
* 1 zhangsan
* 2 lisi
* 3 wangwu
* Set set =map1.entrySet();
* set集合对象
* 1=zhangsan (注意Map集合通过entrySet()方法转换成Set集合,set集合中元素类型是Map.Entry<K,V>)
* 2=lisi (Map.Entry 和String一样,都是一种类型的名字,只不过Map.Entry是静态内部类,是Map中的静态类)
* 3=wangwu --->这个东西是Map.Entry
*
*遍历Map集合
*
*
* */
public static void main(String[] args) {
Map<Integer, String> map=new HashMap<>();
//添加
map.put(1,"zhangsan");
map.put(2,"lisi");
map.put(3,"wangwu");
//通过key获取value
System.out.println(map.get(2));
//获取jzd
System.out.println("键值对"+map.size());
//删除key删除键值对
map.remove(1);
//判断是否包含某个key
System.out.println(map.containsKey(2));
//判断是否包含某个value
System.out.println(map.containsValue("zhangsan"));
//获取所有的value
//第一种方法,获取所有的key 遍历key,从而遍历value
Collection<String> c=map.values();
for (String s:c
) {
System.out.println(s);
}
Set<Integer> keys=map.keySet();
//使用迭代器
Iterator<Integer> k=keys.iterator();
while (k.hasNext()){
Integer ke=k.next();
String value =map.get(ke);
System.out.println(ke+"="+value);
//System.out.println(k.next()+"="+map.get(k.next()));
}
//使用foreach
for (Integer ke:keys
) {
System.out.println(ke+"="+map.get(ke));
}
//第二种方式:Set<Map.Entry<K,V>> entrySet()
//将Map集合转换成Set集合
//Set集合类型是Map.Entry
Set<Map.Entry<Integer,String>> set=map.entrySet();
//遍历Set集合每次取出一个Node
//迭代器
Iterator<Map.Entry<Integer,String>> it= set.iterator();
while (it.hasNext()){
Map.Entry<Integer,String> node=it.next();
Integer key =node.getKey();
String value = node.getValue();
System.out.println(key+"="+value);
}
//foreach
//这种方式效率高
for (Map.Entry<Integer,String> node:set
) {
System.out.println(node.getKey()+"="+ node.getValue());
}
}
}
HashMap集合和Hashtable集合
public class HashMapTest{
/*
* HashMap集合和Hashtable集合
* HashMap集合允许key和value值为null,只允许一个
* Hashtable集合不允许key和value值为null
*
* HashMap集合和Hashtable集合底层是哈希表/散列表数据结构
* 哈希表是数组和单链表的结合体
* 数组在查询效率高
* 单链表在随机增删效率高
*
*
* 放在HashMap集合的key部分的key元素和HashSet集合中的元素需要重写equals()和hashCode()方法
* HashMap集合和Hashtable集合, HashMap集合默认初始化容量是16,,Hashtable集合默认初始化容量是11,默认加载因子是0.75(底层数组容量达到75%,数组开始扩容)
*HashMap初始化容量要是2的倍数,可以达到散列均匀,通过存取效率
* Hashtable集合扩容是*2+1
* */
public static void main(String[] args) {
Map map=new HashMap();
}
}
Properties集合
public class PropertiesTest {
/*
* Properties是一个Map集合,继承了Hashtable,Properties的key和value值都为String类型
* Properties称为属性类对象
* Properties是线程安全的
* */
public static void main(String[] args) {
Properties p=new Properties();
p.setProperty("fds","gsdf");
System.out.println(p.getProperty("fds"));
}
}
TreeSet集合和自定义类型比较排序
public class TreeSetText {
/*
* TreeSet集合底层实际上是TreeMap
* TreeMap集合底层实际上是二叉树
* 放到TreeSet集合中的元素实际上放到了TreeMap集合key部分
* TreeSet集合无序不可重复,但是可以按元素大小排序
* 对自定义类型排序需要重写接口Comparable中的compareTo()ff
* */
public static void main(String[] args) {
Name a1=new Name(1,"dsa");
Name a2=new Name(2,"dad");
Name a3=new Name(3,"re");
Name a4=new Name(4,"fg");
//重写compareTo比较
Set<Name> list= new TreeSet();
list.add(a1);
list.add(a2);
list.add(a3);
list.add(a4);
for (Name i:list
) {
System.out.println(i);
}
//通过比较器接口比较
User u1=new User(2);
User u2=new User(1);
User u3=new User(3);
Set<User> set=new TreeSet<>(new Usercompar());//比较器接口对象,若比较经常切换建议使用这个,可以写别的比较数据
set.add(u1);
set.add(u2);
set.add(u3);
for (User u:set
) {
System.out.println(u);
}
}
}
class Name implements Comparable<Name> {
int age;
String name;
public Name(int age, String name) {
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Name{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Name o) {
if (this.age==o.age)
this.name.compareTo(o.name); //String已经重写了compareTo方法
return this.age-o.age;
}
}
class User {
int age;
@Override
public String toString() {
return "User{" +
"age=" + age +
'}';
}
public User(int age) {
this.age = age;
}
}
class Usercompar implements Comparator{
@Override
public int compare(Object o1, Object o2) {
return ((User)o1).age-((User)o2).age;
}
}
集合工具类Collections
public class collectionsTest {
public static void main(String[] args) {
List<Integer> list=new ArrayList(); //线程不安全
Collections.synchronizedList(list);//线程安全了
list.add(2);
list.add(1);
list.add(3);
Collections.sort(list); //调用集合工具类排序
for (Integer i:list
) {
System.out.println(i);
}
Set<User1> s=new TreeSet<>();
s.add(new User1(2));
s.add(new User1(3));
s.add(new User1(1));
//Collections.sort(s); //只支持List接口
List<User1> list1=new ArrayList<>(s);
Collections.synchronizedList(list1);
Collections.sort(list1);
for (User1 u:list1
) {
System.out.println(u);
}
}
}
class User1 implements Comparable{
int age;
@Override
public String toString() {
return "User1{" +
"age=" + age +
'}';
}
public User1(int age) {
this.age = age;
}
@Override
public int compareTo(Object o) {
return this.age-((User1)o).age;
}
}
IO流
(1)字节流一次读8位二进制
字符流一次读一个字符
(2)IO流四大家族(都是抽象类):
java.io.InputStream 字节流输入流
java.io.OutputStream字节输出流
java.io.Reader字符输入流
java.io.Writer字符输出流
在java中类名以Stream结尾是字节流,以Reader/Weiter结尾是字符流
(3)所有流都实现了 java.io.Closeable 接口,都是可关闭的,都有close()方法
(4)所有的输出流实现了 java.io.Flushable 接口,都是可刷新的(让通道中残余的数据强行输出 完),都有flush()方法
(5)java.io中需要掌握16个流
文件专属流:
java.io.FileInputStream
java.io.FileOutputStream
java.io.FileReader
java.io.FileWriter
转换流(字节流转换字符流)
java.io.BufferedInputStream
java.io.BufferedOutputStream
java.io.BufferedReader
java.io.BufferedWriter
数据专属流
java.io.DataInputStream
java.io.DataOutputStream
标输出流
java.io.PrintReader
java.io.PrintWriter
对象专属流
java.io.ObjectInputStream
java.io.ObjectOutputStream
InputStream 字节流输入流
public class FileInputStreamTest {
/*
* 文件字节输入流,任何类型的文件都可以采用这个流来读
*
* */
public static void main(String[] args) {
FileInputStream fileInputStream=null;
try {
fileInputStream =new FileInputStream("E:\\桌面\\桌面\\d1");
//开始读
//int dataRead =fileInputStream.read();//这个方法返回的是这个“字节”的本身asccll
// System.out.println(dataRead);//读到文件末尾返回-1, 一次只能读一个字节
/*
while (true){
int l=fileInputStream.read();
if (l==-1 ) {
break;
}
System.out.println(l);
}
*/
/* //改造while
int k=0;
while ( (k=fileInputStream.read())!=-1){
System.out.println(k);
}
*/
/*
//以上都是一次读一个字节
//向byte[]数组里面读
byte[]bytes=new byte[4];
//int f=fileInputStream.read(bytes);
//System.out.println(f);//4,返回的是数量不是内容
//将字节转换字符串
//System.out.println(new String(bytes)); //asdf
System.out.println(new String(bytes,0,fileInputStream.read(bytes)));//加范围
//System.out.println(new String(bytes)); //gsdf,只有五位数字最后一位只覆盖了a,其他没有覆盖照常输出
System.out.println(new String(bytes,0,fileInputStream.read(bytes)));
*/
//改进
/*
byte[] bytes=new byte[4];
int newBytes;
while ((newBytes=fileInputStream.read(bytes))!=-1){
System.out.println(new String(bytes,0,newBytes));
}
*/
//int available()返回流中还没有读到字节数量
byte[] bytes=new byte[fileInputStream.available()];//不适合太大文件
System.out.println(fileInputStream.available());
int c=fileInputStream.read(bytes);
System.out.println(new String(bytes));
//loog skip()跳过几个字节不读
fileInputStream.skip(3);
System.out.println(fileInputStream.read());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
if (fileInputStream != null) {//关闭流的前提是流不为null,为null关闭没有意义
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
OupputStream字节输出流
public class FileOutputStreamTest {
public static void main(String[] args) {
FileOutputStream fileOutputStream=null;
try {
fileOutputStream=new FileOutputStream("dd",true); //没有dd文件会自动创文件,若有会先清空文件内容再写入
byte[] bytes={98,45,65,100}; //后面加true就不会清空
fileOutputStream.write(bytes);//b-Ad
fileOutputStream.write(bytes,0,2);//b-Adb- 写一部分
String s="周添加牛逼,6666";
fileOutputStream.write(s.getBytes());
fileOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
文件拷贝
public class Copy {
public static void main(String[] args) {
FileInputStream fileInputStream=null;
FileOutputStream fileOutputStream=null;
try {
fileInputStream=new FileInputStream("E:\\桌面\\桌面\\JavaCode\\java个人理解.png");
fileOutputStream=new FileOutputStream("E:\\桌面\\桌面\\JavaCode\\java个人理解Copy.png");
byte[] b=new byte[1024*1024];
int data;
while ((data=fileInputStream.read(b))!=-1){
fileOutputStream.write(b,0,data);
}
fileOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileInputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
FileReader
public class FileReaderTest {
public static void main(String[] args) {
FileReader reader=null;
try {
reader=new FileReader("dd");
char []chars=new char[4];
int data;
while ((data=reader.read(chars))!=-1){
System.out.println(new String(chars,0,data));
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
FileWriter
public class FileWriterTest {
public static void main(String[] args) {
FileWriter fileWriter=null;
try {
fileWriter=new FileWriter("ff");
char[]chars={'d','f','f','r'};
fileWriter.write(chars);
fileWriter.write("dsfdsgggag");
fileWriter.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fileWriter != null) {
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
BufferedReader
public class BufferedReaderTest {
public static void main(String[] args) throws IOException {
FileReader fileReader=new FileReader("dd");
BufferedReader bufferedReader=new BufferedReader(fileReader);
String s=null;
while ((s=bufferedReader.readLine())!=null) {
System.out.println(s);
}
bufferedReader.close();
}
}
InputStreamReader
public class InputStreamReaderTest {
public static void main(String[] args) throws FileNotFoundException {
FileInputStream fileInputStream=new FileInputStream("dd");
InputStreamReader inputStreamReader=new InputStreamReader(fileInputStream);
BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
}
}
DataOutputStream和DataInputStream
/*
DataOutputStream对数据加密,打印出来是乱码,只能用DataInputStream读
*/
public class DataOutputStreamTest {
public static void main(String[] args) throws IOException {
DataOutputStream dataOutputStream=new DataOutputStream(new FileOutputStream ("ss"));
int i=100;
dataOutputStream.writeInt(i);
dataOutputStream.flush();
dataOutputStream.close();
DataInputStream dataInputStream=new DataInputStream(new FileInputStream("ss"));
int j=dataInputStream.readInt();
System.out.println(j);
dataInputStream.close();
}
}
PrintStream
/*
PrintStream输出到控制台
*/
public class PrintStreamTest {
public static void main(String[] args) throws FileNotFoundException {
//联合起来写
System.out.println("Hello");
//分开写
PrintStream ps=System.out;
ps.println("hh");
//这个不需要手动关闭
PrintStream printStream=new PrintStream(new FileOutputStream("ff"));
System.setOut(printStream); //改变文件输出方向,不在输出到控制台而是输出到ff文件中
System.out.println("fdas");
System.out.println("hh");
}
}
File
/*
File 类和四大家族没有关系,所以不能完成读写
File对应的是文件的目录或者是文件
File是路径的抽象表示
*/
public class Filetest {
public static void main(String[] args) throws IOException {
File file=new File("E:\\file");
System.out.println(file.exists());//判断目录或者文件是否存在false
if (!file.exists()){ //D:\file不存在则创建一个文件
file.createNewFile();
}
if (!file.exists()){//D:\file不存在则创建一个目录
file.mkdir();
}
System.out.println(file.getParent());//获取文件父路径
System.out.println(file.getAbsoluteFile());//获取绝对路径
System.out.println(file.getName());//获取文件名
System.out.println(file.isDirectory());//判断是否是目录
System.out.println(file.isFile());//判断是否是文件
long time=file.lastModified();//毫秒从1970年到现在
Date date=new Date(time);
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String s=simpleDateFormat.format(date);
System.out.println(s);
System.out.println(file.length());//获取文件大小字节
}
}
目录复制
public class CopyAll {
public static void main(String[] args) {
File srcFile =new File("E:\\小黑");
File destFile =new File("E:\\d");
copyDir( srcFile,destFile);
}
/**
* 拷贝目录
* @param srcFile 拷贝源
* @param destFile 拷贝目标
*/
private static void copyDir(File srcFile, File destFile) {
if (srcFile.isFile()){
FileInputStream in=null;
FileOutputStream out=null;
try {
in =new FileInputStream(srcFile);
String h=(destFile.getAbsolutePath().endsWith("\\")?destFile.getAbsolutePath():destFile.getAbsolutePath()+"\\")+srcFile.getAbsolutePath().substring(3);
out =new FileOutputStream(h);
byte []bytes=new byte[1024*1024];
int redcode;
while ((redcode=in.read(bytes))!=-1){
out.write(bytes,0,redcode);
}
out.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
File[] files= srcFile.listFiles();//源下面子目录
for (File f :
files) {
if (f.isDirectory()){
String srcDir=f.getAbsolutePath();
String destDir=(destFile.getAbsolutePath().endsWith("\\")?destFile.getAbsolutePath():destFile.getAbsolutePath()+"\\")+srcDir.substring(3);
System.out.println(destDir);
File n=new File(destDir);
if (!n.exists()){
n.mkdirs();
}
}
copyDir(f,destFile);
}
}
}
ObjectInputStream 和ObjectOutputStream
序列化和反序列化(就是读入写出分成一小份一批一批运输),参与序列化和反序列化的对象,对象类必须实现Serializable接口(系统会自动生成一个序列号,当对象类更改了代码系统又会生成一个新的序列号,但是在读的时候是之前写的信息,系统会报错,所以必须给对象类自定义序列号private static final long serialVersionUID = 1L。java判断一个类是否相同先判断类名,然后是序列号);
注意,通过源码可以发现,Serializable接口是一个标志性接口
public interface Serializable{
}
这个接口中什么代码都没有,他的作用起到标识的作用,java虚拟机看到这个类实现这个接口,可能对这个类实现特需待遇,自动生成序列化版本号
若不想将对象某个属性序列化可以用transient关键字修饰
IO和Properties集合联合
public class test {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream=new FileInputStream("dd");
Properties properties=new Properties();
properties.load(fileInputStream);
System.out.println(properties.getProperty("Account")); //自动将=右边内容输出
System.out.println(properties.getProperty("Password"));
//这样设计的理念
/*
以后经常改变数据,可以单独写到一个文件中,使用程序驱动动态读取。
将来只需要修改这个文件内容,java代码不需要改动,不需要重新编译,
服务器也不需要重启,就可以拿的动态信息
类似以上机制文件被称作配置文件
并且配置文件中的内容格式是
key1=value
key2=value
的时候,我们把这种配置文件叫做属性配置文件
java规范中有要求:属性配置文件一.properties结尾,但不是必须 的
*/
}
}
多线程
什么是进程?什么是线程?
进程是一个应用程序(一个进程是一个软件)
线程是一个进程中的执行场景/执行单元
一个进程可以启动多个线程
对于java程序来说,当DOS命令窗口输入:java HelloWord 回车之后
会先启动JVM,二JVM就是一个进程,
JVM再会启动一个垃圾回收线程负责看护,回收垃圾。
最起码,现在的java程序最起码有垃圾回收线程和一个main主函数线程
举个例子:
阿里巴巴:进程
马云:一个线程
童文红:一个线程
进程A与进程B的内存独立不共享
线程A和线程B:堆内存中和方法区内存共享,但是栈内存独立,一个线程一个栈、
假设启动10个线程就会有10个栈空间,每个栈和每个栈之间互不干扰,各自执行各自的
这就是多线程并发
思考一个问题:使用多线程之后,main方法执行结束,是不是其他线程也结束了?
main方法结束只是主栈结束,主栈空了,其他栈可能还在压栈或者弹栈
分析一个问题:对于单核CPU来说,真的可以做到多线程吗
对于单核CPU来说,由于CPU处理速度极快,线程与线程之间频繁交换给一种错觉
start()方法解释
public class test {
public static void main(String[] args) {
myThread m=new myThread();
m.run();//并不会启动多线程,只是调用方法而已
m.start();//这里会立马在新建一个myThread栈,多线程开始
for (int i=0;i<1000;i++){
System.out.println("主线程执行了"+i);
}
}
/*
start()方法的作用:启动一个分支线程,在JVM开辟一个新的栈空间,执行这段代码后立马瞬间结束,
这段代码作用是开辟新的栈空间,开辟完后就结束了
线程成功启动会自动调用run方法,将run自动压栈,并且run方法在该栈低部
run方法在支栈的底部,main方法在主栈的底部,这两个方法是同级的
*/
}
class myThread extends Thread{
@Override
public void run() {
for (int i=0;i<1000;i++){
System.out.println("myThread线程执行"+i);
}
}
}
java实现线程的两中方式
第一种:编写一个类直接继承java.lang.Thread,重写run()方法
第二种:编写一个类,实现java.lang.Runnable接口,实现run()方法
注意:第二种方法更好,他还可以继承别的类
也可以采用内部类方式创建线程
线程生命周期获取取当前线程对象、对象名字、修改线程名字
public class test1 {
public static void main(String[] args) {
hh l=new hh();
hh l2=new hh();
l.setName("h1");//对线程对象改名
System.out.println(l2.getName());//线程默认名字,Thread-1 ,l线程的默认名Thread-0但是该了,默认名递加
l.start();
l2.start();
}
}
class hh extends Thread{
@Override
public void run() {
for (int i=0;i<1000;i++){
//Thread.currentThread()当前线程对象
//Thread.currentThread().getName()当前线程对象的名字
System.out.println(Thread.currentThread().getName()+i);
}
}
}
sleep()方法、interrupt()方法、更好的线程终止方法
public class test1 {
public static void main(String[] args) {
hh r=new hh();
Thread t=new Thread(r);
t.setName("t");
t.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
//t.interrupt();//当main线程执行到5秒进入这个代码,终止t对象线程
//但是由于太过暴力可以这样
r.newrun=false;
}
}
class hh implements Runnable {
boolean newrun=true;
@Override
public void run() {
for (int i=0;i<10000;i++) {
if (newrun) {
try {
Thread.sleep(1000); //当前线程,记住当前线程
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + i);
} else {
//终止当前程序
//可以对终止前进行一些操作
return;
}
}
}
}
常见的线程调度模型
1.抢占式调度模型
那个线程的优先级比较高,抢到的CPU时间片概率就高一些
java就是这种模式
2.均分式调度模型
平均分配时间片
java提供那些方法和线程调度有关
实例方法:
void setPriority(int newPriority) 设置线程的优先级
int getPriority() 获取线程优先级
最低优先级1
默认5
最高10
(优先级比较高的获取时间片可能会多一些,但也不完全是,大概率是高的)
实例方法:
void join()
合并线程
class MyThread1 extends Thread{
public void doSome(){
MyThread2 t=new MyThread2();
t.join();//当前线程进入阻塞,让t线程先执行,直到t线程结束,当前线程才可以执行
//Thread.yield();//当前线程暂停一下个其他线程
}
}
class MyThread2 extends Thread{
}
线程安全与synchronize()
什么时候在多线程并发的环境下存在安全问题?
1.多线程并发
2.有共享 数据
3.共享数据有修改行为
怎么解决?
线程排队执行(不能并发)称作线程同步机制也叫线程同步
异步编译模型
线程1,线程2,各执行各的,谁也不管谁,异步就是并发
同步
线程1在执行线程2等待直到线程1结束
class Account {
private String account;
private int balance;
public Account(String account, int balance) {
this.account = account;
this.balance = balance;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public int getBalance() {
return balance;
}
public void setBalance(int balance) {
this.balance = balance;
}
//取钱
public void withdrawal(int withdrawalAmount){
/*
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
balance=balance-withdrawalAmount;
//这样是可以卡银行的bug的
*/
/*以下代码是线程排队,不能并发
一个线程把这里的代码全部执行玩,另一个线程才能进来
线程同步机制语法:
synchronize(){
//线程同步代码块
}
synchronize后面小括号中传这个“数据”非常关键
()中写什么是要看你想同步那个线程
这里的共享对象是:账户对象
账户对象是共享的,那么this就是账户对象吧
不一定是this,这里只要是多线程共享的那个对象就行
*/
synchronized (this){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
balance=balance-withdrawalAmount;
}
/*
以上代码块执行原理:
在java语言中,然后一个对象都有“一把锁”其实这把锁就是标记
100个对象,100个锁,一个对象一个锁
1.假设t1和t2线程并发,开始开始执行以上代码肯定有一个先后顺序
2.假设t1先执行了,遇到synchronize,这个时候自动找到“后面共享对象”的对象锁,
并占用,然后执行同步代码,直到结束,才会释放
3.假设t1占有这把锁,t2遇到synchronize关键字,他也
会占用后面对象锁,直到t1结束t2才能执行
这样就达到线程排队执行
这里的共享对象一定要选好
*/
}
}
class AccountThread extends Thread{
private Account account;
public AccountThread(Account account) {
this.account = account;
}
@Override
public void run() {
account.withdrawal(5000);
System.out.println(Thread.currentThread().getName()+ account.getAccount()+"withdrawalBalance"+account.getBalance());
}
}
public class main{
public static void main(String[] args) {
Account account=new Account("act",10000);
Thread t1=new AccountThread(account);
Thread t2=new AccountThread(account);
t1.setName("t1");
t2.setName("t2");
t1.start();
t2.start();
}
java三大变量与线程安全关系
实例变量:堆中,堆只有一个所以线程共享,存在线程安全问题
静态变量:方法区,方法区只有一个所以线程共享,存在线程安全问题
局部变量:栈中,局部变量部共享,一个线程一个栈,不存在安全问题
常量:不存在
成员变量:可能有
局部变量用StringBuilder,不存在线程安全其他,效率高
ArrayList非线程安全
vector线程安全
HashMap Hashset非线程安全
Hashtable线程安全
线程守护
public class test {
public static void main(String[] args) {
Thread t=new B();
t.setName("t");
//启动线程之前设置为守护线程
t.setDaemon(true);
t.start();
for (int i=0;i<4;i++){
System.out.println(Thread.currentThread().getName()+(++i));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
class B extends Thread{
@Override
public void run() {
int i=0;
while (true){
System.out.println(Thread.currentThread().getName()+(++i));
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
定时器
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Data {
public static void main(String[] args) throws ParseException {
Timer t=new Timer();//创建线程守护对象
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date firstTime=sdf.parse("2023-03-17 00:14:50");
t.schedule(new c(),firstTime,1000*5);
//t.schedule(执行任务,第一次执行时间,间隔多久执行一次);
}
}
class c extends TimerTask {
@Override
public void run() {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String srrTime=sdf.format(new Date());
System.out.println(srrTime+"完成一次备份");
}
}
实现线程的第三种方法
wait()和notify()方法
public class test {
public static void main(String[] args) {
List<Integer> list=new ArrayList<>();
Thread thread1= new Thread(new produce(list));
Thread thread2= new Thread(new consume(list));
thread1.setName("生产线程");
thread2.setName("消费线程");
thread1.start();
thread2.start();
}
}
//生产
class produce implements Runnable{
private List list;
public produce(List list) {
this.list = list;
}
private int i=1;
@Override
public void run() {
while (true){
synchronized (list){
if (list.size()>0){
try {
list.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
list.add((i++));
System.out.println(Thread.currentThread().getName()+list.get(0));
list.notifyAll();
}
}
}
}
//消费
class consume implements Runnable{
private List list;
public consume(List list) {
this.list = list;
}
@Override
public void run() {
while (true){
synchronized (list){
if (list.size()==0){
try {
list.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println(Thread.currentThread().getName()+list.get(0));
list.remove(0);
list.notifyAll();
}
}
}
}
反射机制
作用:操作字节码文件,让程序更加灵活
反射机制在java,lang.reflect.*;包下
反射机制相关的重要的类:
java.lang.class:代表整个字节码,代表一个类型,代表一个类
java.lang.reflect.Method:代表字节码中的方法字节码,代表类中的方法
java.lang.reflect.Constructor:代表字节码中的构造方法字节码,代表类中的构造方法
java.lang.reflect.Field:代表字节码中的属性字节码,代表类中的成员变量(静态变量,实例变量)
三种获取字节码文件方式
public class test
{
public static void main(String[] args) {
/*
Class.forName()
1.静态方法
2.方法参数是字符串
3.字符串需要一个完整的类名
4.完整类名必须带有包名
5.如果只想静态代码块(类加载执行)执行,可以用这个方法
*/
Class c1=null;
try {
c1=Class.forName("java.lang.String");//c1代表String.class文件,或者c1代表String类型
Class c2=Class.forName("java.util.Date");//c2代表Data类型
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
/*
java中任何一个对象都有getClass()方法
*/
String s="sad";
Class x=s.getClass();//x代表String字节码文件,String类型
System.out.println(c1==x);//true,判断对象内存地址
/*
java中任何一种类型,都有.class属性
*/
Class a=int.class;
Class b=int.class;
System.out.println(a==b);//true
}
}
通过相对路径获取绝对路径两种方法
package Test;
import java.io.InputStream;
import java.util.Properties;
public class test
{
public static void main(String[] args) throws Exception {
// String path= Thread.currentThread().getContextClassLoader().getResource("hh.properties").getPath();
// System.out.println(path);
// FileReader fileReader=new FileReader(path);
InputStream fileReader=Thread.currentThread().getContextClassLoader().getResourceAsStream("hh.properties");//与包名同级
InputStream fileReader2=Thread.currentThread().getContextClassLoader().getResourceAsStream("Test/gg.properties");//与类名同级
Properties properties=new Properties();
properties.load(fileReader2);
fileReader2.close();
String name=properties.getProperty("name");
System.out.println(name);
}
}
java.lang.reflect.Field
package Test;
import java.lang.reflect.Field;
public class test {
public static void main(String[] args) throws ClassNotFoundException {
Class l=Class.forName("Test.f");
Field[] files= l.getFields();
System.out.println(files.length); //1
for (Field f:files
) {
System.out.println(f.getName()); //i
}
Field [] fields=l.getDeclaredFields();
System.out.println(fields.length); //4
for (Field f:fields
) {
System.out.println(f.getName()); //i,j,k,h
}
}
}
package Test;
public class f {
public int i;
protected int j;
private int k;
boolean h;
}
反射机制访问对象属性
package Test;
import java.lang.reflect.Field;
public class test {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
Class l=Class.forName("Test.f");
Object o= l.newInstance();
Field field=l.getDeclaredField("i");
field.set(o,100);
System.out.println(field.get(o));
Field field1=l.getDeclaredField("k");
field1.setAccessible(true); //打破了封装哟
field1.set(o,66);
System.out.println(field1.get(o));
}
}
package Test;
public class f {
public int i;
protected int j;
private int k;
boolean h;
}
可变长度参数
package Test;
/*
可变长度参数
语法:类型...
可变参数的个数个数是0到n个
可变参数可以当数组看待
可变参数只能有一个,并且在最后
*/
public class test {
public static void main(String[] args) {
h("ztj",1,2,1);
}
public static void h(String s,int...a){
for (int i=0;i<a.length;i++){
System.out.println(a[i]);
}
}
}
java.lang.reflect.Method
package Test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
/*
可变长度参数
语法:类型...
可变参数的个数个数是0到n个
可变参数可以当数组看待
可变参数只能有一个,并且在最后
*/
public class test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class l=Class.forName("Test.f");
Method[] methods=l.getDeclaredMethods();
System.out.println(methods.length); //1
for (Method m:methods
) {
System.out.println(Modifier.toString(m.getModifiers()));//方法修饰类型
System.out.println(m.getReturnType().getSimpleName()); //方法返回类型
System.out.println(m.getName()); // 方法名
Class[] p=m.getParameterTypes();
for (Class par:p
) {
System.out.println(par.getSimpleName()); // 方法参数类型
}
}
//调用方法
Object o=l.newInstance();
Method m=l.getDeclaredMethod("g",String.class,int.class);
Object value=m.invoke(o,"ztj",1);
System.out.println(value);
}
}
package Test;
public class f {
public void g(String s,int i){
}
}
获取一个类的父类的接口
public class test {
public static void main(String[] args) throws ClassNotFoundException {
Class l=Class.forName("java.lang.String");
Class superClass=l.getSuperclass();
System.out.println(superClass.getName());//java.lang.Object
Class []i=l.getInterfaces();
for (Class h:i
) {
System.out.println(h.getName());
/*
java.io.Serializable
java.lang.Comparable
java.lang.CharSequence
java.lang.constant.Constable
java.lang.constant.ConstantDesc
*/
}
}
}