java se的一些知识总结

来源:互联网 发布:玻璃排班优化软件 编辑:程序博客网 时间:2024/06/15 22:30

1、字符串的基本操

java字符串在内存中采用Unicode编码方式,任何一个字符对应两个字节的定长编码。任何一个字符(无论中文还是英文)都算一个字符长度。String有length()方法。

String是不可变对象:字符串一旦创建,对象永远无法改变,但字符串引用可以重新赋值。

String常量池:静态字符串(字面量/常量/常量连接的结果)在常量池中创建,并尽量使用同一个对象,重用静态字符串;对于重复出现的字符串直接量,JVM会首先在常量池中查找,如果存在即返回该对象。

1.1、String的方法:

使用indexOf实现检索:

int indexOf(String str) /  int indexOf(String str,int fromIndex) /  int lastIndexOf(String str)

使用substring获取子串:

String substring(int beginIndex,int endIndex) /  String substring(int beginIndex)

使用trim去掉一个字符串的前面和后面的空字符;

使用charAt返回字符串指定位置的字符:

charAt(int index)

使用startsWith和endsWith检测一个字符串是否以指定字符串开头或结尾;

使用toUpperCase和toLowerCase转换一个字符串的大小写变换;

使用valueOf将其它类型转换为字符串;

split() /  replaceAll() // matches()方法

1.2、StringBuilder与StringBuffer

封装可变的字符串,对象创建后可以通过调用方法改变其封装的字符序列

StringBuilder是非线程安全的,并发处理的,性能稍快;

StringBuffer是线程安全的,同步处理,性能稍慢。

构造方法:public StringBuilder() /  public StringBuilder(String str)

常用方法

StringBuilder  append(String str)追加字符串

StringBuilder insert(int dstOffset,String str)插入字符串

StringBuilder delet(int start,int end)删除字符串(含头不含尾)

StringBuilder replace(int start,int end,String str)替换字符串

StringBuilder reverse()字符串反转

2、正则表达式

[abc] /  [^abc] /  [a-z0-9] /  [a-z&&[^bc]]

.  \d , \w , \s , \D , \W , \S

?,+,*,{n},{n,m},{n,}

分组:();分组时可以使用“|”表示“或”关系;

边界匹配符:^,&

2.1、String正则API:

matches(正则表达式)方法:将一个字符串与正则表达式进行匹配;

split()方法:String[] split(String regex):将一个字符串以正则表达式所表示的字符串为分界符拆分成字符串数组;

replaceAll()方法:String replaceAll(String regex,String replacement):将字符串中匹配正则表达式所表示的字符串替换成replacement。

注意:equals与==的区别:

==用于比较变量的值,可以用于任何引用类型,如果用于引用类型,比较的是两个引用变量存储的值(地址信息),判断两个变量是否指向相同的对象;

equals是Object的方法,重写以后可以用于两个对象的内容是否“相等”;Object默认的equals方法的比较规则同==。

3、包装类与自动拆装箱

包装类是不可变类,在构造了包装类后,不允许更改包装在其中的值;包装类是final的,不能定义它们的子类。

int——>Integer,byte——>Byte,short——>Short,long——>Long,float——>Float,double——>Double,boolean——>Boolean,char——>Character;

例:String转换成int型,前提值String表示的是int型:如String str = "123";     int a = Integer.parserInt(str);

抽象类Number是byte,short,int,long,float,double的父类,Number的子类提供了将数值转换为byte,short,int,long,float,double的方法:即doubleValue、intValue、floatValue等;

自动拆装箱:自动“拆箱”和“装箱”是依靠JDK5的编译器在编译期的“预处理”工作;是编译器认可的而不是虚拟机;

Integer a = 100;//装箱——>  Integer a = Integer.valueOf(100)

Integer b = 200;----------------------------------------------------------

Integer c = a+b;//先拆箱在装箱——>Integer c = Integer.valueOf(a.intValue+b,intValue)

4、日期操作

4.1、Date:

getTime()与setTime()方法;

Date date = new Date();//获取当前时间

long time = date.getTime();//1970年1月1日零时至此时此刻的毫秒数

date.setTime(time);//设置时间

4.2、SimpleDateFormat:

构造方法:

SimpleDateFormat();

SimpleDateFormat(String pattern);//格式:yyyy-MM-dd HH:mm:ss










方法:

final String format(Date date);//Date——>String

Date parse(String source);//String——>Date

4.3、Calendar

Calendar提供了一个类方法getInstance,一次获得此类型的一个通用对象,即:Calendar  c = Calendar.getInstance();

设置日期及时间分量 set();

ca.set(Calendar.YEAR, 2017);

ca.set(Calendar.MONTH,Calendar.JANUARY);// ca.set(Calendar.DATE, 28);

ca.set(Calendar.DAY_OF_WEEK, Calendar.TUESDAY);

获取日前及时间分量 get();

int year = ca.get(Calendar.YEAR);

//注意:月份是从0开始的

int month = ca.get(Calendar.MONTH)+1;

int date1 = ca.get(Calendar.DATE);

int week = ca.get(Calendar.WEEK_OF_MONTH);

//注意:一周的第一天是周日

int day = ca.get(Calendar.DAY_OF_WEEK);

getActualMaximum方法:返回指定日历字段可能拥有的最大值

ca.getActualMaximum(Calendar.DAY_OF_YEAR)

void add(int field,int mount);为给定的时间分量的值加上给定的值若给定的值为负数则是减去给定的值;

Date getTime();// Calendar——>Date:

void setTime(Date d);// Date——>Calendar:

5、集合的操作

集合Collection是一个接口,定义了集合相关的操作方法,其有两个子接口:List和Set;

List:可重复集,有序的。List的两个常用实现类ArrayList和LinkedList,分别用动态数组和链表的方式实现了List接口;ArrayList更适合随机访问而LinkedList更适合插入和删除。

Set:不可重复集,大部分无序。

集合中存储的都是引用类型元素,并且集合只保存每个元素对象的引用,而并非将元素对象本身存入集合。

5.1、集合的方法:

boolean add(E e)方法:向集合中添加元素,若添加成功则返回true,否则返回false;

boolean addAll(Collection c)方法:传入一个集合;

boolean contains(Object o)方法:判断给定的元素是否被包含在集合中,若包含则返回true,否则返回false(根据元素的equals方法进行比较你,所以有必要重写equals方法。);

boolean containsAll(Collection c)方法:判断是否包含一个集合;

int size(),void clear(),boolean isEmpty();boolean remove(E e),boolean removeAll(Collection c),

基于下标的get和set方法:

E get(int index);获取集合中指定下标的元素,下标从0开始;

E set(int index,E element);将给定的元素存入给定的位置,并将原位置元素返回。

void add(int index,E element);将给定的元素插入指定的位置;原位置及后续元素都顺序后移;

E remove(int index);删除指定位置的元素并将被删除的元素返回。

List的subList方法用于获取子List;subList获取的子List与原List占有相同的存储空间,对子List操作会影响原List。

List<E> subList(起始,结束)含头不含尾;

5.2、迭代器、增强型for循环:

5.2.1、迭代器:

迭代器是一个接口,集合在重写Collection的iterator()方法时利用内部类提供了迭代器的实现。

迭代器提供了统一遍历集合元素的方式,其提供了用于遍历集合的两个方法:

boolean hasNext(),E next();

在使用迭代器遍历集合时,不能通过集合的remove方法删除元素,否则会抛出并发更改异常,可以通过迭代器自身提供的remove方法来删除通过next()迭代出来的元素。

void remove();

注意:在调用remove()方法前必须通过迭代器next()方法迭代过元素,那么删除的就是这个元素。并且不能再次调用remove()方法,除非再次调用next()方法;

5.2.2、增强型for循环(新循环):

java5.0之后推出的一个新特性,只用于遍历集合和数组。

for(元素类型 e : 集合或数组){循环体}

新循环并非新的语法,而是在编译过程中,编译器会将新循环转换为迭代器,所以新循环本质上是迭代器。

5.3、泛型在集合中的应用

5.4、List:

List转换为数组:List的toArray方法;实际上该方法是在Collection中定义的,所有集合都具备这个功能;<T>T[] toArray(T[] a)。

数组转换为List:Arrays类中提供了一个静态方法asList;转换后的集合不能增删元素,否则会抛出异常,并且对集合元素的修改会影响数组对应的元素。

List排序:

(1)、Collections时集合的工具类;提供了用于排序的sort方法;

void sort(集合);对给定的集合进行自然排序;

(2)、实现Comparable接口,重写抽象方法int compareTo(T t);

(3)、采用Compatator接口回调的方式,可以在操作中临时指定排序的规则,要重写int compare(T o1,T o2)方法;

5.5、队列(Queue)和栈(Stack):

5.5.1、队列:

队列遵循先进先出(FIFO)的原则;

方法:boolean offer(E e);将一个对象添加到队尾,若成功则返回true;

E poll();从队首删除并返回一个元素;

E peek();返回队首的元素但并不删除。

5.5.2、栈:

栈遵循这先进后出(FILO)的原则;

入栈为push,出栈为pop

5.6、查询表

5.6.1、Map接口:

Map接口定义的集合又称查找表,用于存储所谓的“Key—Value”影射对,Key可以看成是Value的索引,作为Key的对象在集合中不可以重复。

Map接口最常用的实现类是内部为Hash表实现的HashMap和内部为排序二叉树实现的TreeMap。

5.6.2、方法:

V put(K key,V value);存入元素,如果集合中已经包含该Key,则操作将替换该Key所对应的Value,返回该Key原来所对应的Value(如果没有,则返回null)。

V get(K key);返回参数key所对应的Value对象,如果不存在,则返回null。

boolean containsKey(K key);若Map中包含给定的key则返回true,否则返回false。

5.6.3、hashCode方法:

作为HashMap的key元素的equals方法与hashcode方法,两个方法的返回的结果直接影响着散列表的查询性能,当两个key的hashcode值一样,意味着他们在散列桶 (HashMap中维护的数组)的相同位置,但若这两个key的equals比较结果不为true,则在HashMap中就会形成链表,这样的情况多了HashMap的查询性能会降低很多。 所以应当妥善处理作为Key元素的类的equals方法与hashcode方法的重写。

对于重写了equals方法的对象,一般要妥善的重写继承自Object类的hashCode方法;

重写hashCode方法需要注意两点

一致性:应当与equals方法保持一致,即:当两个对象equals比较为true时,hashcode方法返回的数字必须相同,反过来则不是必须的,但应当尽量保证两个对象若hashcode方法返回的数字相同时equals比较也为true,否则在HashMap中会出现链表影响查询性能。

稳定性:在参与equals比较的属性值没有发生过变化的前提下多次调用hashcode方法返回的数字不能变化。

5.6.4、Map的遍历:

有三种方式:遍历所以的Key;遍历所有的Key—Value;遍历所有的Value;

(1)遍历所有的Key:Set<K> keySet();该方法会将所有的key存入一个Set集合后返回。

(2)遍历所有的Key—Value:Set<Entry<K,V>> entrySet();该方法会将当前Map中的每一组key—value对封装一个Entry对象并存入一个Set集合后返回。

(3)遍历所有的Value(比较少用):Collection<V> values();将所有的value存入一个集合后返回。

6、文件操作

File类只能用于表文件(目录)的信息(名称、大小等),不能对文件的内容进行访问。

构造方法:

File(String pathname);将给定路径名字符串转换成抽象路径名称来创建一个新File实例,抽象路径要尽量写相对路径,并且目录的层级分隔符不要直接写“/”或“\”,应使用File.separator这个常量来表示,以避免不同系统带来的差异。

File(File parent,String child);根据parent抽象路径名称和child路径名字符串创建一个新File实例。

其它方法:

boolean isFile();判断当前对象是否是文件;

boolean isDirectory();判断当前对象是否是一个目录;

long length();表示文件所占用的字节量;

boolean exists();判断该File所表示的文件或目录是否存在;

boolean createNewFile();如果指定的文件不存在并且成功创建返回true,若指定的文件已经存在则返回false;

boolean delete();删除文件或目录;若删除的是目录,必须保证目录为空时才能成功删除;

boolean mkdir();创建目录;

boolean mkdirs();创建多级目录;

File[] listFiles();返回此路径名表示的目录中的文件或目录,如果目录为空,那么数组也为空,如果抽象路径名不表示一个目录或者发生I/O错误,则返回null;

6.1、FileFilter接口:

此接口的实例可传递给File类的listFiles(FileFilter)方法,用于返回满足该过滤器要求的子项。

File[] listFiles(FileFilter filter);

6.2、RandomAccessFile:

该类的读写是基于指针的操作;在对文件进行随机访问操作时有两个模式,只读模式("r")和读写模式(“rw”);

构造方法:RandomAccessFile(String filename,String mode) /  RandomAccessFile(File file,String mode)

字节数据读写操作:

write(int d);在当前指针所在位置出写入一个字节,是将参数int的“低8位”写出;

int read();返回值范围是0~255;如果返回的是-1表示读取到了文件的末尾;每次读取后自动移动文件指针;

void write(byte[] d);该方法会根据当前指针所在位置处连续写出给定数组中的所有字节;

void write(byte[] d,int offset,int len);连续写出数组中的部分字节,从数组的offset处开始,连续len个字节;

int read(byte[] d);批量读取字节,将读取到的字节存放的数组中,返回值为实际读取到的自节量;

close()方法;在对文件访问的操作全部结束后,要调用close()方法释放与其关联的所有系统资源。

将字符串按照指定编码转换为字节:调用String的getBytes(指定字符集)方法如:byte[] buf = "helloworld".getBytes("GBK");

将字符串按照默认编码转换为字节:调用String的getBytes()方法;

字节——>字符串:new String(byte[] d,指定字符集);或者new String(byte[] d);

6.3、文件指针操作:

long getFilePointer()方法,用于获取当前RandomAccessFile指针位置;

void seek(long pos)方法,移动指针的位置;

int skipBytes(int n)方法,跳过一些数量较少的字节;

void writeInt(int d);将int值写出,还有void writeDouble(double d)等;相应的有int readInt();  double readDouble()等。

7、基本IO操作

流根据方向可以分为输入流输出流,流的方向是基于程序作为参照方向,输入是从外界进入程序的方向,是读操作,写操作相反;输入流是用来读取数据,输出流是用来写出数据。

流分为节点流(低级流)与处理流(高级流),读写一定要有节点流;节点流是实际负责搬运数据的流,数据源明确;处理流是用来处理其他流的,可以基于其处理的流对数据进行加工,从而简化我们的读写操作。

InputStream是所有字节输入流的父类,OutputStream是所有字节输出流的父类。

文件流是一对字节流,数据源为文件;FileInputStream集成自InputStream,FileOutputStream集成自OutputStream。

缓冲流是一对高级流。

IS与OS常用方法:

int read();int read(byte[] d);void write();void write(byte[] d);

7.1、文件流(低级流):

构造方法:

字节输出流:FileOutputStream(File file);FileOutputStream(String filename);若指定的文件已经包含内容,那么当使用FOS对其写入数据时,会将该文件中原有数据全部清除;

追加模式:FileOutputStream(File file,boolean append);FileOutputStream(String filename,boolean append);若第二个参数为true,则在文件末尾追加写数据;

字节输入流:FileInputStream(File file);FileInputStream(String name)

7.2、缓冲流(高级流)

缓冲输出流:BufferedOutputStream(fos);有一个方法:void flush();清空缓冲区,将缓冲区中的数据强制写出;

缓冲输入流:BufferedInputStream(fis)

7.3、对象流:

对象流是一对高级流;

序列化:将对象转化为一个字节序列的过程;方法:void writeObject(Object o);将给定的对象转换为一个字节序列后写出;

反序列化:将一个字节转化其对应的对象的过程;方法:Object readObject();从流中读取字节并转换为对应的对象;

注意:需要序列化的对象所属的类必须实现Serializable接口,作为可序列化的标志,通常实现该接口的类需要提供一个常量serialVersionUID表明该类的版本,避免反序列化时出现的不兼容问题;

transient关键字:对序列化后得到的字节序列进行“瘦身”;该关键字修饰的属性在序列化时其值将被忽略。

7.4、字符流(高级流):

Reader是字符输入流的父类;常用方法:int read();   int read(char[] c);

Writer是字符输出流的父类;常用方法:void write(int d); void write(char[] c); void write(char[] c,int offset,int len);  void write(String str)将给定的字符串写出;

字符流是以字符为单位读写数据的,一次处理一个unicode;

字符流的底层仍然是基本的字节流,所以字符流只是简化了我们在字符串与字节之间的转化工作

转换流:

InputStreamReader:字符输入流;使用该流可以设置字符集;按照指定字符集从流中按照该编码将字节转换为字符并读取;

构造方法:InputStreamReader(InputStream in,String charsetName);  InputStreamReader(InputStream in);

OutputStreamWriter:字符输出流;使用该流可以设置字符集;按照指定字符集字符转换为对应字节后通过该流写出。

构造方法:OutputStreamWriter(OutputStream out,String charsetName);OutputStreamWriter(OutputStream out);

7.5、缓冲字符输出流与缓冲字符输入流:

缓冲字符输出流:PrintWriter:具有自动行刷新功能;PW可以传入字节流,也可以传入字符流;

构造方法:PrintWriter(File file);PrintWriter(String filename);PrintWriter(OutputStream out);PrintWriter(OutputStream out,boolean autoFlush);PrintWriter(Writer,writer);PrinterWriter(Writer writer,boolean autoFlush);其中boolean autoFlush参数用于表示PrintWriter是否具有自动行刷新。

void println()方法,可以自动行刷新;在输出目标数据后自动输出一个系统支持的换行符,

缓冲字符输入流:BufferedReader;

String readLine();按行读取字符串;


字节流与字符流的区别:

字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是用到缓冲区的。

字节流在操作文件时,即使不关闭资源(close方法),文件也能输出;但是如果字符流不使用close方法时,就不会输出内容,说明字符流是用缓冲区的,并且可以使用flush方法进行刷新缓冲区刷新,这时才能在不使用close方法的情况下输出内容。

8、异常

8.1、异常的捕获与处理:

8.1.1、Throwable,Error和Exception

Java异常结构中定义有Throwable类,ExceotionError是其派生的两个子类。其中Exception表示由于网络故障、文件损坏、设备错误、用户输入非法等情况导致的异常,这类异常是可以通过Java异常捕获机制处理的。而Error表示Java运行时环境出现的错误,例如:JVM内存溢出等。

8.1.2、try—catch—finally:

try {...} 语句指定了一段代码,该段代码就是一次捕获并处理例外的范围,在执行过程中,该段代码可能会产生并抛出一种或几种类型的异常对象,它后面的catch语句分别对这些异常做相应的处理;

如果没有列外产生,所有的catch代码段都被略过不执行;在catch语句块中是对异常进行处理的代码,catch中声明的异常对( catch(SomeException e) )封装了异常事件发生的信息,在catch语句块中可以使用这个对象的一些方法获取这些信息;每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常catch捕获的异常类型由上至下顺序应是子类到父类的应当养成一个习惯,在最后一个catch中捕获Exception,这可以避免try块中的代码出现一个未捕获的异常导致程序中断;

finally语句为异常处理提供一个统一的出口,使得在控制流程转到程序其它部分以前,能够对程序的状态作统一管理;无论try所指定的程序块中是否抛出例外,finally所指定的代码都要被执行,通常在finally语句中可以进行资源的释放工作,如关闭打开的文件、删除临时文件等;finally语句块只能定义在try语句块之后,或者最后一个catch语句块之后,且只能定义一次。

8.1.3、throw关键字:

当程序发生错误而无法处理的时候,会抛出对应的异常对象;若想要自行抛出异常,可以使用“throw”关键词,并生成指定的异常对象。

当一个方法中使用throw抛出一个异常时,就要在该方法上使用throws声明这个异常的抛出以告知调用者注意并需要解决;只有RuntimeException及其子类异常抛出时不需要这样做,除此之外这个操作是必须的,否则编译器编译不通过。当一个方法使用throws声明了某些异常的抛出时,那么调用当前方法的代码必须处理这个异常。

调用一个含有throws声明异常抛出的方法时处理该异常的方式有两种try-catch捕获并处理;继续在当前方法上使用throws抛出这些异常;

8.1.4、throws关键字:

程序中会声明许多方法,这些方法中可能会因某些错误而引发异常,若不希望直接在这个方法中处理这些异常,而是希望调用这个它的方法来统一处理,这时可以使用“throws”关键词来声明这个方法将会抛出异常;

重写方法时的throws:

当使用继承时,在父类的某个方法上声明了throws某些异常,而在子类中重写该方法时,可以做以下的操作:

不处理异常(重新定义时不再设定throws);可以仅声明父类方法中声明的部分异常 ;可以声明父类方法中抛出异常的子类型异常 ;

但是不能做以下操作不允许抛出额外异常 ;不允许抛出父类方法抛出异常的父类型异常

8.2、自定义异常:自定义异常通常用于业务逻辑的错误等。

8.3、RuntimeException:

Java异常可以分为可检测异常非检测异常

可检测异常:可检测异常经编译器验证,对于声明抛出异常的任何方法,编译器将强制执行处理或声明规则,不捕捉这个异常,编译器就通不过,不允许编译

非检测异常:非检测异常不遵循处理或者声明规则。在产生此类异常时,不一定非要采取任何适当操作,编译器不会检查是否已经解决了这样一个异常

RuntimeException 类属于非检测异常,因为普通JVM操作引起的运行时异常随时可能发生,此类异常一般是由特定操作引发。但这些操作在java应用程序中会频繁出现。因此它们不受编译器检查与处理或声明规则的限制 。

常见的RuntimeException异常:

IllegalArgumentException

抛出的异常表明向方法传递了一个不合法或不正确的参数

NullPointerException

当应用程序试图在需要对象的地方使用 null 时,抛出该异常

ArrayIndexOutOfBoundsException

当使用的数组下标超出数组允许范围时,抛出该异常

ClassCastException

当试图将对象强制转换为不是实例的子类时,抛出该异常

NumberFormatException

当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。

8.4、Throwable中的一些方法:

void printStackTrace();输出错误堆栈信息;

String getMessage;返回有关异常事件的信息;

9、线程及通信(TCP、UDP)

进程(process):所谓进程就是一块包含了某些资源的内存区域。操作系统利用进程把它的工作划分为一些功能单元。进程中所包含的一个或多个执行单元称为线程(thread)。进程还拥有一个私有的虚拟地址空间,该空间仅能被它所包含的线程访问。线程只能归属于一个进程并且它只能访问该进程所拥有的资源。当操作系统创建一个进程后,该进程会自动申请一个名为主线程或首要线程的线程。操作系统中有若干个线程在"同时"运行。通常,操作系统上运行的每一个应用程序都运行在一个进程中,例如:QQ,IE等等。

注:进程并不是真正意义上的同时运行,而是并发运行。

线程(thread):一个线程是进程的一个顺序执行流。同类的多个线程共享一块内存空间和一组系统资源,线程本身有一个供程序执行时的堆栈。线程在切换时负荷小,因此,线程也被称为轻负荷进程。一个进程中可以包含多个线程。

线程与进程的区别:

一个进程至少有一个线程。线程的划分尺度小于进程,使得多线程程序的并发性高。另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。

线程在执行过程中与进程的区别在于每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。

从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用来实现进程的调度和管理以及资源分配。

线程的使用场合:

线程通常用于在一个程序中需要同时完成多个任务的情况,我们可以将每个任务定义为一个线程,使他们得以一同工作;也可以用于在单一线程中可以完成,但是使用多线程可以更快的情况。

9.1、线程的创建:

创建线程有两种方式:

方式一:继承Thread并重写run方法;

有两点不足:由于需要继承Thread,而java又是单继承原则,这就导致当前类不能在继承其它类,很多时候在实际开发中会出现继承冲突问题;而且由于在在线程内部重写了run方法定义了当前线程要执行的任务,这就导致了线程与任务有一个强耦合关系,不利于线程的重用。

方式二:单独定义线程任务,实现Runnable接口;

使用匿名内部类完成线程的两种方式的创建:

注意:

启动线程要调用start方法,不要直接调用线程的run方法,当线程启动后,run方法会自动被执行。

线程启动后,何时运行,运行多久都听线程调度管理;线程对于线程调度的工作是不可控的;

即:线程何时被分配CPU时间不可控,分配多长时间不可控;线程不能主动向线程调度要时间只能被动被分配;线程调度会尽可能将CPU时间均匀的分配给所有线程,但不保证一个线程一次这样规律的切换。

9.2、线程的操作:

Thread.currentThread方法:Thread的静态方法currentThread方法可以用于获取运行当前代码片段的线程;

Thread提供了获取线程信息的相关方法:

long getId():返回该线程的标识符;

String getName():返回该线程的名字;

int getPriority():返回线程的优先级;分为1-10;1最低;10最高;Thread.MIN_PRIORITY:最低;Thread.MAX_PRIORITY:最高;Thread.NORM_PRIORITY:默认

void setPriority(int priority):设置线程的优先级;

Thread.state getState():获取线程的状态;

boolean isAlive():测试线程是否处于活动状态;

boolean isDaemon():测试线程是否是守护线程;void setDaemon(boolean):设置守护线程;守护线程的特点:当进程只剩守护线程时,守护线程强制终止;GC就是运行在一个守护线程上的;当一个进程中的所有前台线程都结束后,进程结束,这时进程中的所有正在运行的后台线程都会被强制中断。

boolean isInterrupted():测试线程是否已经中断;

Thread的静态方法sleep用于使当前线程进入阻塞状态static void sleep(long ms);该方法会使调用该方法的线程进入阻塞状态指定毫秒,当阻塞指定毫秒后,线程会重新进入到Runnable状态,等待分配时间片;该方法会声明抛出一个InterruptedException异常,所以在使用该方法时需要捕获这个异常。

Thread的静态方法yieldstatic void yield();该方法使当前线程主动让出当次时间片回到Runnable状态,等待分配时间片;

Thread的方法join:void join();该方法是用来协调线程同步的,当一个线程调用另一个线程join方法时,该线程会进入阻塞状态,直到另一个线程执行完毕才会解除阻塞;该方法会声明抛出一个InterruptedExceptoin

9.3、线程同步:

9.3.1、synchronized关键字:

多线程并发安全问题:当多个线程访问同一资源时,由于线程切换时机不确定,可能导致多个线程执行代码出现混乱,导致程序执行出现问题,严重时可能导致系统瘫痪。解决并发安全问题,就是要将多个线程""改为"排队"执行。

synchronized关键字是java中的同步锁;

当一个方法被Synchronized修饰后,那么该方法为"同步方法",即多个线程不能同时进入方法内部执行;方法上使用synchronized,那么锁对象就是当前方法所属对象,即:this

有效的缩小同步范围可以在保证安全的前提下提高并发效率:synchronized (同步监视器—锁对象引用){ //代码块} 

使用同步块要注意同步监视器对象(上锁对象)的选取:通常使用this即可;若多个线程调用同一个对象的某些方法时,也可以将这个对象上锁。比如,在一个方法中多个线程调用同一个集合的方法:list.add(xxx),这时可以将这个集合list作为上锁的对象。原则:多个线程看到的上锁对象是同一个时,才有同步效果。

静态方法锁:静态方法被synchronized修饰后,该方法是一个同步静态方法,任何时候都有同步效果;静态方法上锁的对象是当前类的类对象,类对象(Class类型实例),每个类在JVM加载时,JVM都会实例化一个Class类型的实例用于描述加载的这个类,而在JVM内部,每个类都有且只有一个Class类型的实例与之对应。静态方法锁的就是这个对象。

互斥锁:当synchronized修饰两段不同代码,但是同步监视器对象相同时,这两段代码就具有了互斥性,多段代码也可以。

死锁:两个线程都在等待对方先施放锁。

线程池:线程池主要解决两个问题:控制线程数量,线程过多会导致CPU过度切换,资源消耗大,拖慢系统,严重时可能导致系统崩溃;重用线程,线程频繁创建与销毁会给系统带来很大负担,所以应当重用线程。线程服务完成后不关闭该线程而是将该线程还回到线程池中。一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。

线程池有以下几种实现策略:

Executors.newCachedThreadPool()

创建一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。

Executors.newFixedThreadPool(int nThreads)

创建一个可重用固定线程集合的线程池,以共享的无界队列方式来运行这些线程。

Executors.newScheduledThreadPool(int corePoolSize)

创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行。

Executors.newSingleThreadExecutor()

创建一个使用单个 worker 线程的 Executor,以无界队列方式来运行该线程。

将集合转换为线程安全的:List中的ArrayList和LinkedList都不是线程安全的;Set中的HashSet也不是线程安全的;Map中的HashMap也不是线程安全的;使用集合的工具类Collections可以将现有的集合或Map转换为线程安全的

9.4、通信

9.4.1、Socket简介:

socket通常称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。

应用程序通常通过“套接字”向网络发出请求或者应答网络请求。Socket和ServerSocket类库位于java .net包中。ServerSocket用于服务端,Socket是建立网络连接时使用的。在连接成功时,应用程序两端都会产生一个Socket实例,操作这个实例,完成所需的会话。

获取本地地址和端口号:

java.net.Socket为套接字类,其提供了很多方法;

其中我们可以通过Socket获取本地的地址以及端口号。int getLocalPort()该方法用于获取本地使用的端口号

InetAddress getLocalAddress()该方法用于获取套接字绑定的本地地址

使用InetAddress获取本地的地址方法:String getCanonicalHostName()获取此 IP 地址的完全限定域名。

String getHostAddress()返回 IP 地址字符串(以文本表现形式)。代码如下:

Socket socket = new Socket("localhost",8088);

InetAddress add = socket.getLocalAddress();//获取本地地址信息

System.out.println(add.getCanonicalHostName());

System.out.println(add.getHostAddress());

System.out.println(socket.getLocalPort());

获取远端地址和端口号:

Socket也提供了获取远端的地址以及端口号的方法:

int getPort()

该方法用于获取远端使用的端口号 。

InetAddress .getInetAddress()

该方法用于获取套接字绑定的远端地址 。

Socket socket = new Socket("localhost",8088);

InetAddress inetAdd = socket.getInetAddress();

System.out.println(inetAdd.getCanonicalHostName());

System.out.println(inetAdd.getHostAddress());

System.out.println(socket.getPort());

获取网络输出流与网络输入流:

通过Socket获取输入流与输出流,这两个方法是使用Socket通讯的关键方法。封装了TCP协议的Socket是基于流进行通讯的,所以我们在创建了双方连接后,只需要获取相应的输入与输出流即可实现通讯。

InputStream getInputStream()

该方法用于返回此套接字的输入流。

OutputStream .getOutputStream()

该方法用于返回此套接字的输出流。

Socket socket = new Socket("localhost",8088);

InputStream in = socket.getInputStream();

OutputStream out = socket.getOutputStream(); 

void close()方法:当使用Socket进行通信完毕后,要关闭Socket以释放系统资源。

9.4.2、Socket通信模型:

Server端的ServerSocket监听:

java.net.ServerSocket是运行于服务端应用程序中。通常创建ServerSocket需要指定服务端口号,之后监听Socket的连接。监听方法为:Socket accept()该方法是一个阻塞方法,直到一个客户端通过Socket连接后,accept会封装一个Socket,该Socket封装与表示该客户端的有关的信息。通过这个Socket与该客户端进行通信。

代码如下:

//创建ServerSocket并申请服务端口8088

ServerSocket server = new ServerSocket(8088);

/*方法会产生阻塞,直到某个Socket连接,并返回请求连接的Socket*/

Socket socket = server.accept();

Client端的Socket连接:

当服务端ServerSocket调用accept方法阻塞等待客户端连接后,我们可以通过在客户端应用程序中创建Socket来向服务端发起连接。

需要注意的是,创建Socket的同时就发起连接,若连接异常会抛出异常。 我们通常创建Socket时会传入服务端的地址以及端口号。

代码如下:

//参数1服务端的IP地址,参数2:服务端的服务端口

Socket socket = new Socket(“localhost”,8088);

10、XML语法及解析

XMl用途:XML 指可扩展标记语言(EXtensible Markup Language),是独立于软件和硬件的信息传输工具,应用于 web 开发的许多方面,常用于简化数据的存储和共享。

10.1、基本语法:

元素:XML 元素指的是从(且包括)开始标签直到(且包括)结束标签的部分;元素可包含其他元素、文本或者两者的混合物;元素也可以拥有属性。

属性:元素可以在开始标签中包含属性,属性 (Attribute) 提供关于元素的额外(附加)信息;属性通常提供不属于数据组成部分的信息,但是对需要处理这个元素的应用程序来说却很重要;XML 属性必须加引号,属性值必须被引号包围,不过单引号和双引号均可使用;如果属性值本身包含双引号,那么有必要使用单引号包围它,或者可以使用实体引用。

XML对大小写是敏感的;XML要求每个元素必须由起始标签和关闭标签组成,关闭标签与起始标签的名字相同,写法上多一个“/”;XML要求必须有根元素,所谓根元素就是不被其它元素包围(不含有父元素),并且根元素只能有一个;XML要求所有元素必须正确的嵌套;起始标记与结束标记不能在不同元素之间交叉定义。

CDATA段:格式:< ! [ CDATA [ 文本内容 ] ] >:当在xml中某一段内容想作为普通信息看待,而其中又出现了大量的xml敏感字符时,可以使用CDATA段来解决。

10.2、解析XML:

SAX解析方式SAX(simple API for XML)是一种XML解析的替代方法,相比于DOM,SAX是一种速度更快,更有效的方法,它逐行扫描文档,一边扫描一边解析,而且相比于DOM,SAX可以在解析文档的任意时刻停止解析;

优点: 解析可以立即开始,速度快,没有内存压力;

缺点: 不能对节点做修改。

DOM解析方式DOM (Document Object Model, 即文档对象模型) 是 W3C 组织推荐的处理 XML 的一种方式,DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点);

优点:把xml文件在内存中构造树形结构,可以遍历和修改节点;

缺点: 如果文件比较大,内存有压力,解析的时间会比较长。

10.2.1、读取XML:

使用DOM解析XML文档的过程:创建SAXReader;使用SAXReader读取XML文档并生成Document对象,这一步就是DOM耗时资源的地方,因为DOM在读取XML文档时就会将XML文档所有内容读取并加载到内存,所以这个预处理较慢,并且内容存入内存所以消耗系统资源;通过Document获取根元素;通过根元素根据XML文档 结构逐级获取子元素,以达到获取XML文档信息的目的。

使用SAXReader需要导入dom4j-full.jar包,其是DOM4J的一个核心API,用于读取XML文档。

attribute方法:

Element的attribute方法用于获取当前元素的属性信息,其方法定义为:

Attribute attribute(int index)

获取当前元素的指定属性,index为索引,从0开始。

Attribute attribute(String name)

获取当前元素的指定名字的属性。

例:

获取当前元素的第一个属性:Attribute attr = element.attribute(0);

获取当前元素的name属性:Attribute attr = element.attribute("name");

属性的两个方法String getName() : 获取属性的名字;String getValue(): 获取属性的值 

10.2.2、写XML:

生成XML文档的大致步骤:创建一个document表示一个XML文档;向文档中添加根元素;按照预定的格式从根元素开始逐级添加子元素;创建XMLWriter;将document对象通过XMLWriter写出生成xml文档。

10.3、XPath:

XPath 是一门在 XML 文档中查找信息的语言,XPath 可用来在 XML 文档中对元素和属性进行遍历。

10.3.1、路径表达式语法:

斜杠(/)作为路径内部的分割符;同一个节点有绝对路径和相对路径两种写法;路径(absolute path)必须用"/"起首,后面紧跟根节点,比如/step/step/...;相对路径(relative path)则是除了绝对路径以外的其他写法,比如 step/step, 也就是不使用"/"起首;"."表示当前节点;".."表示当前节点的父节点;nodename(节点名称):表示选择该节点的所有子节点;"/":表示选择根节点;"//":表示选择任意位置的某个节点;"@": 表示选择某个属性 。

举列说明:

代码如下:

常用表达式如下:

10.3.2、谓语:

所谓"谓语条件",就是对路径表达式的附加条件;所有的条件,都写在方括号"[]"中,表示对节点进行进一步的筛选。 

常用谓语如下图所示:

10.3.3、通配符:

通配符的使用如下:

"*"表示匹配任何元素节点;"@*"表示匹配任何属性值;node()表示匹配任何类型的节点。

常用通配符用法如下图所示:


1 0
原创粉丝点击