包装类--Math 类--Arrays 类--System 类--日期类--集合--泛型--JUnit--多线程基础--互斥锁

81 阅读26分钟

包装类

包装类的分类

包装类和基本数据的转换

演示包装类和基本数据类型的相互转换,这里以int和Integer演示。

1)jdk5前的手动装箱和拆箱方式,装箱:基本类型->包装类型,反之,拆箱

2)jdk5以后(含jdk5)的自动装箱和拆箱方式

3)自动装箱底层调用的是valueOf方法,比如Integer.valueOf()

4)其它包装类的用法类似,

//演示 int <--> Integer 的装箱和拆箱

//jdk5 前是手动装箱和拆箱

//手动装箱 int->Integer

                int n1 = 100;

                Integer integer = new Integer(n1);

                Integer integer1 = Integer.valueOf(n1);

//手动拆箱 //Integer -> int

                 int i = integer.valueOf(n1);

//自动装箱 int->Integer 

              Integer integer2 = n2;

//底层使用的是

                Integer.valueOf(n2)

//自动拆箱

               Integer->int 

              int n3 = integer2;

//底层仍然使用的是valueOf

Integer主要是看范围 -128 ~ 127 就是直接返回 //,否则,就 new Integer(xx)

Integer 类和 Character

System.out.println(Integer.MIN_VALUE); // 返回最小值

System.out.println(Integer.MAX_VALUE);// 返回最大值

System.out.println(Character.isDigit('a'));// 判断是不是数字

System.out.println(Character.isLetter('a'));// 判断是不是字母

System.out.println(Character.isUpperCase('a'));// 判断是不是大写

System.out.println(Character.isLowerCase('a'));// 判断是不是小写

System.out.println(Character.isWhitespace('a'));// 判断是不是空格

System.out.println(Character.toUpperCase('a')); 转成大写

System.out.println(Character.toLowerCase('A'));// 转成小写

 

String 类

String 类的理解和创建对象

创建 String 对象的两种方式

1)方式一:直接赋值 String s= "wyx”

2)方式二:调用构造器 String s = new String("wyx");

区别

方式一:直接赋值 String s= "wyx";

方式二:调用构造器 String s2 = new String("wyx");

1.方式一:先从常量池查看是否有"wyx"数据空间,如果有,直接指向;如果没有则重新创建,然后指向。s最终指向的是常量池的空间地址

2.方式二:先在堆中创建空间,里面维护了value属性,指向常量池的wyx空如果常量池没有"wyx",重新创建,如果有,直接通过value指向。最终指的是堆中的空间地址。

3.画出两种方式的内存分布图

字符串的特性

说明

1)String是一个final类,代表不可变的字符序列

2)字符串是不可变的。一个字符串对象一旦被分配,其内容是不可变的1.以下语句创建了几个对象?画出内存布局图。

String s1 = "hello";

s1="haha"; //1min

/创建了2个对象

小结:

        底层是 StringBuilder sb = new StringBuilder(); 

        sb.append(a);      sb.append(b);sb是在堆中,

        并且append是在原来字符串的基础上追加的

重要规则:

                        String c1 = "ab" + "cd";常量相加,看的是池。 

                        String c1 = a+b;变量相加,是在堆中

String 类的常见方法

说明

String类是保存字符串常量的。每次更新都需要重新开辟空间,效率较低,因此jawa设计者还提供了StringBuilder 和 StringBuffer 来增强String的功能并提高效率。

String 类的常见方法一览

StringBuffer 类

基本介绍

  1. Java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删
  2. 很多方法与String相同,但StringBuffer是可变长度的。
  3. StringBuffer是一个容器。

String VS StringBuffer

  1. String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是更改地址,效率较低//private final char value[];
  2. StringBuffer保存的是字符串变量,里面的值可以更改,每次
  3. StringBuffer的更新实际上可以更新内容,不用每次更新地址,效率较高/char[] value;//这个放在堆

String 和 StringBuffer 相互转换

//方式 1 使用构造器

//注意: 返回的才是 StringBuffer 对象,对 str 本身没有影响

        StringBuffer stringBuffer = new StringBuffer(str);

//方式 2 使用的是 append 方法

        StringBuffer stringBuffer1 = new StringBuffer();

        stringBuffer1 = stringBuffer1.append(str)

        StringBuffer ->String

//方式 1 使用 StringBuffer 提供的 toString 方法

        String s = stringBuffer3.toString();

//方式 2: 使用构造器来搞定

        String s1 = new String(stringBuffer3)

StringBuilder 类

1)一个可变的字符序列。此类提供一个与StringBuffer兼容的API,但不保证同步(StringBuilder 不是线程安全)。该类被设计用作 StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。如果可能,建议优先采用该类因为在大多数实现中,它比StringBuffer要快[后面测]。

2)在 StringBuilder上的主要操作是 append 和 insert方法,可重载这些方法,以接受任意类型的数据。

 

3) StringBuilder 和 StringBuffer 均代表可变的字符序列,方法是一样的,所以使用和StringBuffer一样,

//1. StringBuilder 继承 AbstractStringBuilder 类

//2. 实现了 Serializable ,说明 StringBuilder 对象是可以串行化(对象可以网络传输,可以保存到文件)

//3. StringBuilder 是 final 类, 不能被继承

//4. StringBuilder 对象字符序列仍然是存放在其父类 AbstractStringBuilder 的 char[] value; // 因此,字符序列是堆中

//5. StringBuilder 的方法,没有做互斥的处理,即没有 synchronized 关键字,因此在单线程的情况下使用 // StringBuilder  stringBuilder = new StringBuilder()

String、StringBuffer 和 StringBuilder 的比较

1)StringBuilder 和 StringBuffer非常类似,均代表可变的字符序列,而且方法也一样

2)String:不可变字符序列,效率低,但是复用率高。

3)StringBuffer:可变字符序列、效率较高(增删)、线程安全,看源码

4)StringBuilder:可变字符序列、效率最高、线程不安全

5)String使用注意说明:

string s="a";//创建了一个字符串

s+="b";/实际上原来的"a"字符串对象已经丢弃了,现在又产生了一个字符串s+"b"(也就是"ab")。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能=>结论:如果我们对String做大量修改,不要使用String

String、StringBuffer 和 StringBuilder 的选择

Math 类

基本介绍

Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数

方法一览

Arrays 类

Arrays 类常见方法

System 类

System 类常见方法

1)exit退出当前程序

2)arraycopy:复制数组元素,比较适合底层调用,一般使用Arrays.copyOf完成复制数组

int[] src={1,2,3};

int[] dest = new int[3];

System.arraycopy(src, 0, dest, 0, 3);

3)currentTimeMillens:返回当前时间距离1970-1-1的毫秒数

4)gc:运行垃圾回收机制 System.gc();

BigInteger 和 BigDecimal 类

应用场景:

1)Biglnteger适合保存比较大的整型

2)BigDecimal适合保存精度更高的浮点型(小数)

 BigInteger  BigDecimal常见方法

1)add加                               2)subtract减

3)multiply乘                       4) divide除

日期类

第一代日期类

第二代日期类

  1. 第二代日期类,主要就是Calendar类(日历)。
  2. public abstract class Calendar extends Object implements Serializable,Cloneable Comparable Calendar
  3. Calendar类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY OF MONTH、HOUR等日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法

第三代日期类

DateTimeFormatter 格式日期

DateTimeFormat dtf = DateTimeFormatter.ofPattern(格式);

String str = dtf.format(日期对象);

类似于Date

提供了一系列和Date类转换的方式Instant->Date:

Date date = Date.from(instant);Date->Instant:

Instant instant = date.tolnstant):

第三代日期类更多方法

LocalDateTime类

MonthDay类:检查重复事件

是否是闰年

增加日期的某个部分

使用plus方法测试增加时间的某个部分

使用minus方法测试查看一年前和一年后的日期

集合

1)可以动态保存任意多个对象,使用比较方便!

2)提供了一系列方便的操作对象的方法:add、remove、set、get等3)使用集合添加,删除新元素的示意代码-简洁了

集合的框架体系

Collection 接口和常用方法

Collection 接口实现类的特点

1)collection实现子类可以存放多个元素,每个元素可以是Object

2)有些Collection的实现类,可以存放重复的元素,有些不可以

3)有些Collection的实现类,有些是有序的(List),有些不是有序(Set)

4)Collection接口没有直接的实现子类,是通过它的子接口Set和 List来实现的

Collection 接口遍历元素方式 1-使用使用 Iterator(迭代器)

基本介绍

1)Iterator对象称为迭代器,主要用于遍历 Collection集合中的元素。2)所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象,即可以返回一个迭代器。

3)Iterator的结构.[看一张图]

4)Iterator 仅用于遍历集合,Iterator本身并不存放对象。

提示:在调用iterator.next()方法之前必须要调用iterator.hasNext()进行检测。若不调用,


且下一条记录无效,直接调用it.next()会抛出NoSuchElementException异常。

 


Collection 接口遍历对象方式 2-for

List 接口和常用方法

List 接口基本介绍

List接口是 Collection接口接口 

1)List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复

2)List集合中的每个元素都有其对应的顺序索引,即支持索引。

3)List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素。

JDKAPI中List接口的实现类:

List 接口和常用方法

常用的 ArrayList LinkedList和Vector

List 接口的常用方法

  1. boolean addAll(int index, Collection eles):从 index位置开始将 eles 中的所有元素添加
  2. Object get(int index):获取指定 index 位置的元素
  3. int indexOf(Object obj):返回 obj 在集合中首次出现的位置
  4. int lastIndexOf(Object obj):返回 obj 在当前集合中末次出现的位置
  5. Object remove(int index):移除指定 index 位置的元素,并返回此元素
  6. Object set(int index, Object ele):设置指定 index 位置的元素为 ele , 相当于是替换.
  7. List subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合

/ 注意返回的子集合 fromIndex <= subList < toIndex

List 的三种遍历方式 [ArrayList, LinkedList,Vector]

ArrayList 底层结构和源码分析

ArrayList 的注意事

1) permits all elements, including null , ArrayList 可以加入null,并且多个

2) ArrayList是由数组来实现数据存储的

3) ArrayList 基本等同于Vector,除了ArrayList是线程不安全(执行效率高)看源码        在多线程情况下,不建议使用ArrayList

ArrayList 的底层操作机制源码分析(重点,难点.)

1)ArrayList中维护了一个Object类型的数组elementData. transient Object[] elementData; //transient表示瞬间,短暂的,表示该属性不会被序列号

2)当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。

3)如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。


示意图:

Vector 底层结构和源码剖析

Vector 的基本介绍

//如果 需要的数组大小 不够用,就扩容 , 扩容的算法

//newCapacity = oldCapacity + ((capacityIncrement > 0) ?

// capacityIncrement : oldCapacity);

//就是扩容两倍.

Vector 和 ArrayList的比较

LinkedList 底层结构

LinkedList 的全面说

1)LinkedList底层实现了双向链表和双端队列特点

2)可以添加任意元素(元素可以重复),包括null

3)线程不安全,没有实现同步

LinkedList底层操作机制

1)LinkedList底层维护了一个双向链表

2)LinkedList中维护了两个属性first和last分别指向首节点和尾节点

3)每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表.

4)所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。

模拟一个简单的双向链表

LinkedList 的增删改查案例

  1. linkedList.remove(); // 这里默认删除的是第一个结点
  2. linkedList.set(1, 999); //修改某个结点对象
  3. /get(1) 是得到双向链表的第二个对象Object o = linkedList.get(1)
  4. //因为 LinkedList 是 实现了 List 接口, 遍历方式

System.out.println("===LinkeList 遍历迭代器====");

Iterator iterator = linkedList.iterator();

while (iterator.hasNext()) {

Object next = iterator.next();

System.out.println("next=" + next);

}

ArrayList 和 LinkedList 比较

Set 接口和常用方法

Set 接口基本介绍

1)无序(添加和取出的顺序不一致),没有索引

2)不允许重复元素,所以最多包含一个null


3)JDK APl中Set接口的实现类有:

Set 接口的常用方法

和List 接口一样, Set 接口也是 Collection的子接口 因此 常用方法和 Collection 接口一样.

Set 接口的遍历方式

1.可以使用迭代器

2.增强for

3.不能使用索引的方式来获取

Set 接口实现类-HashSet

HashSet 的全面说明

1)HashSet实现了Set接口

2)HashSet实际上是HashMap,

3)可以存放null值,但是只能有一个null

4)HashSet不保证元素是有序的,取决于hash后,再确定索引的结果.(即,不保证存放元素的顺序和取出顺序一致)

5)不能有重复元素/对象.在前面Set接口使用已经讲过

HashSet 底层机制说明

分析HashSet底层是HashMap, HashMap底层是(数组+链表+红黑树)

>分析HashSet的添加元素底层是如何实现(hash()+equals())

 

>分析HashSet的扩容和转成红黑树机制

Set 接口实现类-LinkedHashSet

LinkedHashSet的全面说明

 1)LinkedHashSet是 HashSet的子类

2)LinkedHashSet底层是一个 LinkedHashMap,底层维护了一个数组+双向链表

3)LinkedHashSet根据元素的 hashCode值来决定元素的存储位置,同时使用链表维护元素

的次序(图),这使得元素看起来是以插入顺序保存的。

4)LinkedHashSet不许添重复元素

Map 接口和常用方法

Map 接口和常用方法

注意:这里讲的是JDK8的Map接口特点

1)Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value2)Map中的key和 value可以是任何引用类型的数据,会封装到HashMap$Node对象中

3)Map中的 key不允许重复,原因和HashSet一样,前面分析过源码

4)Map中的value可以重复

5)Map的key可以为 null, value也可以为null,注意 key 为null只能有一个,,,value为null,可以多个.

6)常用String类作为Map的 key

7)key和 value之间存在单向一对一关系,即通过指定的key总能找到对应的 value

8)Map存放数据的key-value示意图,一对k-v是放在一个HashMap$Node中的,有因为Node实现了 Entry接口,有些书上也说一对k-v就是一个Entry(如图)

Map 接口常用方法

remove:根据键删除映射关系

get:根据键获取值

size:获取元素个数

isEmpty:判断个数是否为0

clear:清除 k-v

containsKey:查找键是否存在

Map 接口遍历方法

  1. containsKey:查找键是否存在
  1. keySet:获取所有的键
  2. entrySet:获取所有关系k-v
  3. values:获取所有的值

迭代器

System.out.println("----使用 EntrySet 的 迭代器(第 4 种)----");

Iterator iterator3 = entrySet.iterator();

while (iterator3.hasNext()) {

        Object entry = iterator3.next();

//System.out.println(next.getClass());//HashMap$Node实现-> Map.Entry (getKey,getValue)

//向下转型 Map.Entry

        Map.Entry m = (Map.Entry) entry;

        System.out.println(m.getKey() + "-" + m.getValue()

Map 接口实现类- HashMap

HashMap 小结

1)Map接口的常用实现类:HashMap、Hashtable和Properties。

2)HashMap是Map接口使用频率最高的实现类。

3) HashMap 是以 key-val 对的方式来存储数据(HashMap$Node类型)

4)key不能重复,但是值可以重复,允许使用null键和null值

5)如果添加相同的key,则会覆盖原来的key-val,等同于修改.(key不会替换,val会替换)

6)与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的.(jdk8的hashMap底层数组+链表+红黑树)

7)HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有synchronized

HashMap 底层机制及源码剖析

HashMap 底层机制及源码剖

>扩容机制[和HashSet相同]

1)  HashMap底层维护了Node类型的数组table,默认为null

2)  当创建对象时,将加载因子(loadfactor)初始化为0.75.

3)  当添加key-val时,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key和准备加入的key相是否等,如果相等,则直接替换val;如果不相等需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够,则需要扩容。

4)  第1次添加,则需要扩容table容量为16,临界值(threshold)为12(16*0.75)

5)以后再扩容,则需要扩容table容量为原来的2倍(32)临界值为原来的2倍,即24,依次类推

6)   在Java8中,如果一条链表的元素个数超过 TREEIFY THRESHOLD(默认是8)并且table的大小 >= MIN TREEIFY CAPACITY(默认64),就会进行树化(红黑树)

Map 接口实现类-Hashtable

HashTable 的基本介绍

1)存放的元素是键值对:即K-V

2)hashtable的键和值都不能为null,否则会抛出NullPointerException3)hashTable使用方法基本上和HashMap一样

4) hashTable 是线程安全的(synchronized), hashMap 是线程不安全的

Hashtable 和HashMap对比

Map-Properties

基本介绍

1.Properties类继承自Hashtable类并且实现了Map接口,也是使用一种键值对的形式来保存数据。

2.他的使用特点和Hashtable类似

3. Properties还可以用于从xxx.properties文件中,加载数据到Properties类对象并进行读取和修改

总结-开发中如何选择集合实现类(记住)

Collections工具类

Collections工具类介绍

1)Collections是一个操作 Set、List和 Map等集合的工具类

2)Collections中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作14.17.2排序操作:(均为static方法)

2.1)reverse(List):反转 List中元素的顺序

2.2)shuffle(List):对 List集合元素进行随机排序

2.3)sort(List):根据元素的自然顺序对指定 List集合元素按升序排序

2.4)sort(List,Comparator)根据指定的 Comparator产生的顺序对 List集合元素进行排序

2.5)swap(List, int, int):将指定 list集合中的i处元素和j处元素进行交换

排序操作:(均为 static 方法)

查找、替换

泛型

使用传统方法的问题分析

1)不能对加入到集合ArrayList中的数据类型进行约束(不安全)

2)遍历的时候,需要进行类型转换,如果集合中的数据量较大,对效率有影响

泛型的理解和好处

1)编译时,检查添加元素的类型,提高了安全性

2)减少了类型转换的次数,提高效率[说明]

3)不再提示编译警告

泛型介绍

理解:泛(广泛)型(类型) => Integer, String,Dog

1)泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题

2)在类声明或实例化时只要指定好需要的具体的类型即可。

3)Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮

4)泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型

泛型的语法

泛型的声明

interface 接口<T>{}和 class类<K,V>{}

比如:List,ArrayList

说明:

1)其中,T,K,V不代表值,而是表示类型。

2)任意字母都可以。常用T表示,是Type的缩写

泛型的实例化

要在类名后面指定类型参数的值(类型)。

如:

  1. List<String> strList = new ArrayList<String>()
  2. List<String> strList = new ArrayList< >()
  3. Iterator<Customer> iterator = customers.iterator();

泛型使用的注意事项和细节

1. interface List<T>{}, public class HashSet<E>{).等等

说明:T,E只能是引用类型

看看下面语句是否正确?:

  1. List<Integer> list = new ArrayList<Integer>(); /OK
  2. List<int> list2 = new ArrayList<int>();/错误

2.在给泛型指定具体类型后,可以传入该类型或者其子类类型

3.泛型使用形式

  1. List<Integer> list1 = new ArrayList<Integer>();
  2. List<Integer> list2 = new ArrayList<>();

3.如果我们这样写 List list3 = new ArrayList();默认给它的泛型是[<E>E就是Object]

自定义泛型类

>基本语法

class类名<T,R.>{/.….表示可以有多个泛型

成员}

>注意细节

1)普通成员可以使用泛型(属性、方法)

2)使用泛型的数组 不能初始化 。

因为数组在 new 不能确定 T 的类型就无法在内存开空间   

3)静态方法中不能使用类的泛型

        因为静态是和类相关的,在类加载时,对象还没有创建所以,如果静态方法和静态属性使用了泛型,JVM 就无法完成初始化

4)泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)

5)如果在创建对象时,没有指定类型,默认为Object

如:

 

1. Tiger 后面泛型,所以我们把 Tiger 就称为自定义泛型类

2, T, R, M 泛型的标识符, 一般是单个大写字母

3. 泛型标识符可以有多个

自定义泛型接口

>基本语法

interface接名<T, R..>{}

>注意细节

1)接口中,静态成员也不能使用泛型(这个和泛型类规定一样)

2)泛型接口的类型,在继承接口或者实现接口时确定

3)没有指定类型,默认为Object

如:

自定义泛型方法

>基本语法

修饰符<T,R.>返回类型方法名(参数列表)

>注意细节

1.泛型方法,可以定义在普通类中,也可以定义在泛型类中

2.当泛型方法被调用时,类型会确定

3. public void eat(E e) {},修饰符后没有<T,R.> eat方法不是泛型方法,而是使用了泛型

泛型的继承和通配符

1)泛型不具备继承性

List<Object> list = new ArrayList<String>();错误示列

2)<?>:支持任意泛型类型

3)<?extends A>:支持A类以及A类的子类,规定了泛型的上限

4)<?super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限

JUnit

为什么需要 JUnit

1.一个类有很多功能代码需要测试,为了测试,就需要写入到main方法中

2.如果有多个功能代码测试,就需要来回注销,切换很麻烦

3.如果可以直接运行一个方法,就方便很多,并且可以给出相关信息,就好了->Junit

基本介绍:

1.JUnit是一个Java语言的单元测试框架

2.多数Java的开发环境都已经集成了JUnit作为单元测试的工具

java 绘图坐标体系

下图说明了Java坐标系。坐标原点位于左上角,以像素为单位。

在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素

坐标体系 - 像素

1.绘图还必须要搞清一个非常重要的概念-像素一个像素等于多少厘米?

2.计算机在屏幕上显示的内容都是由屏幕上的每一个像素组成的。例如,计算机显示器的分辨率是800×600,表示计算机屏幕上的每一行由800个点组成,共有600行,整个计算机屏幕共有480000个像素。像素是一个密度单位,而厘米是长度单位,两者无法比较

绘图原理

Component类提供了两个和绘图相关最重要的方法:

1.paint(Graphicsg)件外观

2.repaint()刷新件外。

当组件第一次在屏幕显示的时候,程序会自动的调用paint()方法来绘制组件

在以下情况paint()将会被调用:

1.窗口最小化,再最大化

2.窗口的大小发生变化

3.repaint方法被调用

Graphics 类

  1. 画直线 drawLine(int x1,int y1,int x2,int y2)
  2. 画矩形边框 drawRect(int x, int y, int width, int height)
  3. 画椭圆边框 drawOval(int x, int y, int width, int height)
  4. 填充矩形 fillRect(int x, int y, int width, int height)
  5. 填充椭圆 fillOval(int x, int y, int width, int height)
  6. 图片 drawlmage(Image imp, int x, int y, .)
  7. 画字符串 drawString(String str, int x, int y)
  8. 设置画笔的字体 setFont(Font font)
  9. 设置画笔的颜色 setColor(Color c)

java 事件处理机制

基本说明

java事件处理是采取“委派事件模型"。当事件发生时,产生事件的对象,会把此"信息”传递给"事件的监听者"处理,这里所说的"信息"实际上就是java.awt.event事件类库里某个类所创建的对象,把它称为“事件的对象"。

示意图

多线程基础

线程相关概念

自己理解:为了完成特定的任务的一组指令的集合

进程

1.是指运行中的程序

2.进程是程序的一次执行过程,或是正在运行的一个程序。是动态过程:有它自身的产生、存在和消亡的过程
3.并发:同一个时刻,多个任务交替执行,造成一种“貌似同时”的错觉,简单的说,单核cpu实现的多任务就是并发。


4.并行:同一个时刻 多个任务同时执行。多核cpu可以实现并行。并发和并行可以切换

 

线程基本使用

创建线程的两种方式

  1. 继承Thread类,重写 run方法


start0() 是本地方法,是 JVM 调用, 底层是 c/c++实现 //真正实现多线程的效果是 start0(), 而不是 run

2.实现Runnable接口,重写 run方法

1.java是单继承的,在某些情况下一个类可能已经继承了某个父类,这时在用继承Thread类方法来创建线程显然不可能了。

2.java设计者们提供了另外一个方式创建线程,就是通过实现Runnable接口来创建线程’

Thread thread = new Thread(T) //因为接口不能直接调用得用类

thread.start();

线程如何理解

继承 Thread vs 实现 Runnable 的区别

1.从java的设计来看,通过继承Thread或者实现Runnable接口来创建线程本质上没有区别,从jdk帮助文档我们可以看到Thread类本身就实现了Runnable接口

2.实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制,建议使用Runnable

线程终止

基本说明

1.当线程完成任务后,会自动退出。

2.还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式

常用方法第一组

  1. setName  设置线程名称,使之与参数 name相同
  2. getName   返回该线程的名称
  3. start   使该线程开始执行; Java虚拟机底层调用该线程的 start0方法
  4. run  调用程对象run方法;
  5. setPriority     更改线程的优先级
  6. getPriority   获取线程的优先级
  7. sleep  在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
  8. interrupt 中断线程

注意事项和细节

  1. start底层会创建新的线程,调用run,run就是一个简单的方法调用,不会启动新线程
  2. 线程优先级的范围
  3. interrupt,中断线程,但并没有真正的结束线程。所以一般用于中断正在休眠线程
  4. sleep:线程的静态方法,使当前线程休眠

常用方法第二组

  1. yield:线程的礼让。让出cpu,让其他线程执行,但礼让的时间不确定,所以也不一定礼让成功
  2. join:线程的插队。插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务

用户线程和守护线程

  1. 用户线程:也叫工作线程,当线程的任务执行完或通知方式结束
  2. 守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束
  3. 常见的守护线程:垃圾回收机制

线程的生命周期

JDK 中用 Thread.State 枚举表示了线程的几种状

线程状态转换图

线程的同步

Synchronized线程同步机制

  1. 在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性
  2. 也可以这里理解:线程同步,即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作

同步具体方法-Synchronized

分析同步原理

互斥锁

基本介绍

1.Java语言中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。

2.每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

3.关键字synchronized来与对象的互斥锁联系。当某个对象用synchronized修饰时表明该对象在任一时刻只能由一个线程访问

4.同步的局限性:导致程序的执行效率要降低

5.同步方法(非静态的)的锁可以是this,也可以是其他对象(要求是同一个对象)

6.同步方法(静态的)的锁为当前类本身。

注意事项和细节

1.同步方法如果没有使用static修饰:默认锁对象为this

2.如果方法使用static修饰,默认锁对象:当前类.class

3.实现的落地步骤:

  1. 需要先分析上锁的代码
  2. 选择同步代码块或同步方法
  3. 要求多个线程的锁对象为同一个即可!

线程的死锁

基本介绍

多个线程都占用了对方的锁资源,但不肯相让,导致了死锁,在编程是一定要避免死锁的发生

释放锁

1.当前线程的同步方法、同步代码块执行结束

        案例:上厕所,完事出来

2.当前线程在同步代码块、同步方法中遇到break、return。

        案例:没有正常结束,叫他修改bug,不得已出来

3.当前线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致异常结束

        案例:进去之后,发现忘带纸,不得已出来

4. 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁。

        案例:吃饭付款时忘记带钱了,回去取钱,在来吃饭

下面操作不会释放锁

1. 线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行,不会释放锁

        案例:写作业 写的过程中突然睡着了

2. 线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起该线程不会释放锁。

        案例:正在打代码 有人叫出去有事 但是电脑没有关机

提示:应尽量避免使用suspend()和resume()来控制线程,方法不再推荐使用


本章笔记是观看韩顺平的JAVA的视频和在网上找的资料 以及自己的理解总结出来的笔记希望可以帮助大家,感谢大家的耐心观看 如有错误请即使联系我 我会及时修正