Java基础知识补充

来源:互联网 发布:淘宝买k粉暗语 编辑:程序博客网 时间:2024/06/14 16:14

补充内容

1.split

split可以把串分解为片语(token)。此动作,俗称“打散”。

需要注意的是,其中的参数并不是“分隔串”,而是一个“正则表达式”

String s = "xyz,abc,123";

String[] ss = s.split(",");

这种用法是正确的。因为,逗号并不是正则表达式的关键字。如果想把“12+25”分解为“12”和“25”,就不能像下面这样写了:

String s = "12+25";

String[] ss = s.split("+");

这是因为“加号”在正则表达式中有特殊的含义。如果希望作为分隔符的就是“+”,则可以采用转义的办法来表达。

String[] ss = s.split("[+]");

或者

String[] ss = s.split("\\+");

其中,有些奇怪的是第二种写法。之所以写两个反斜线,是因为,反斜线也是java串中的转义符号,所以此处是经过了两次转义。第一次是java转义,第二次是正则表达式的转义

2.java.util.StringTokenizer

有的时候,使用StringTokenizer更容易对串进行分解工作。这是类可根据我们提供的分隔符号把一个串,分解为多个token,分解的时候,也可以包含分隔符本身,也可以不包含

String s = "23+45-(3+5*2)";

StringTokenizer st = new StringTokenizer(s,"+-*/()",true);

while(st.hasMoreTokens()){

System.out.println(st.nextToken());

}

另外,countTokens()可以返回tokens的数目。

3.正则表达式

正则表达式代表字符序列的一定的“样式”。我们可以去判断,给定的样式是否与某个串相匹配。也可以从一个序列中去提取出匹配的子串来。

String s1 = "  AD12  ";

String s2 = "\\s*[A-Za-z]{1,3}[0-9]{1,4}\\s*";

System.out.println(Pattern.matches(s2,s1));

[0-9A-Fa-f]  含义就是:0|1|2|3...|A|B|C|D|E|F|a|...

matches()方法判断给定的样式s2是否与s1相匹配。它的返回值是boolean类型。上面这段代码判断s1是否符合excel表的单元格“相对表示法”。

\s 表示空白字符

方括号内表示字符本身。有一些限定数量的量词,它们可能是:

* 表示0个或多个

+ 表示1个或多个

? 表示0个或1个

{m,n}  表示至少m个,至多n个

{m} 表示正好m个

下面是判断手机号码的一个例子:

String s1 = "1350555117";

String s2 = "(138|136|135)[0-9]{8}";

System.out.println(Pattern.matches(s2,s1));

下面是判断身份证号码的例子:

String s1 = "320111197103254419";

String s2 = "[0-9]{6}19[0-9][0-9][0-1][0-9][0-2][0-9][0-9]{4}";

System.out.println(Pattern.matches(s2,s1));

 

Pattern除了能够判断是否匹配,还能够把已经匹配上的子串从母串中分离出来。

String s1 = "56+14-5*(2+6)-56+48";

String s2 = "\\+|\\-|\\*|\\/|\\(|\\)";

 

Pattern p = Pattern.compile(s2);

Matcher m = p.matcher(s1);

 

while(m.find()){

System.out.println(m.group() + "," + m.start() + "," + m.end());

}

上例中,寻找 +-*/ 及括号的位置,输出匹配项,并其起始和结束位置

Matcher类代表一个遍历串的匹配工具。它用find()搜索下一个匹配项,group()输出匹配项的内容,start(), end()给出匹配项出现的开始和结束位置。

String s1 = "2+5*3/5-4";

String s2 = "[0-9]{1,2}\\*[0-9]{1,2}|[0-9]{1,2}\\/[0-9]{1,2}";

Pattern p = Pattern.compile(s2);

Matcher m = p.matcher(s1);

if(m.find()){

String t = m.group();

s1 = m.replaceFirst("kkk");

}

System.out.println(s1);

上面的代码,在s1中搜索第一个出现的乘法或除法算式,并把它用“kkk”去代替。此处,replaceFirst()方法,把第一处匹配用另一个串去代替。这个方法很有用。我们可以利用这个动作去对四则运算求值。

4.JDK5.0新特性:foreach

foreach是c#中的特性,jdk5.0开始也引入了这个特性。

这个特性,只对数组和容器使用

1) 对数组的用法:

int[] x = {10,20,30,50};

for(int k: x){

System.out.println(k);

}

2) 对容器的用法

Vector x = new Vector();

x.add("xyz");

x.add("abc");

x.add("abc");

 

for(Object k: x){

System.out.println(k);

}

5.JDK5.0新特性:enum

如果我们需要定义很多个常量,用final修饰是不方便的

在许多语言中都有“枚举”类型。jdk5.0也引入了这个特性。

定义如下:

enum ZhiCheng

{

ZHU_GONG, GONG_CHENG_SHI, GAO_GONG;

}

使用如下:

ZhiCheng x;

x = ZhiCheng.GAO_GONG;

if(x==ZhiCheng.ZHU_GONG) ....

6.JDK5.0新特性:泛型

jdk5.0以前的版本中,数据结构一般都是用Object为操作元素,这样在写入和读出的时候,需要转换,比较烦琐。而且,java在对动态类型进行管理的时候,也要耗费时间。

泛型技术,类似于c++中的类模板的技术就是定义类时,产生的是模板类型,在使用类的时候,再去指定它需要的类型,这时才把类真正固定下来

Vector<String> a = new Vector<String>();

a.add("abc");

a.add("1234");

a.add("xyz");

Iterator<String> i = a.iterator();

while(i.hasNext()){

String s = i.next();

System.out.println(s);

}

我们可以像java的泛型类一样,创建自己的泛型类。

class MyStack<T>{

private Object[] m_data;

private int m_num;

public MyStack(){

m_data = new Object[100];

m_num = 0;

}

public void push(T x){

m_data[m_num] = x;

m_num++;

}

public T pop(){

m_num--;

return (T)m_data[m_num];

}

}

使用这个泛型类:

MyStack<String>  a;

a = new MyStack();

 

a.push("abc");

a.push(new Integer(555));

System.out.println(a.pop());

java的泛型与c++很不一样。c++采用的是模板的替换技术,为每个不同的类型生成了新的版本。java的泛型采用“拭去”技术。本质上仍就是Object,只是java在适当的时机进行了适当的类型转换,从而把“不安全的转换”这个敏感的工作交给编译器来完成

 

可以去查找关于泛型的高级话题:

类型范围的限制:class <T extends Shape> ...

类型通配符: void f(Collection<?> x){ ... }

泛型方法:<T> void f(Collection<T> x){ ... }

7.java反射

java为什么能够实现多态?必须在某种机制,能够在运行的时候,准确地判定一个对象的真实类型。这称为运行时类型识别(RTTI)

java中,保存类型信息的类为Class。由它可获得类型的类名,方法,属性等信息。任何一个装入内存的类或者接口,java都会为它创建一个Class类的对象来保存该类型的详细信息。

与许多语言不同,java并不是一上来就把所有的类都加载入内存。它在用到一个类的时候,才会去查找它的Class对象,如果不存在,才去加载类

正是通过了Class对象,java才能完成由那个类创建对象的工作。

Object中的getClass()方法,返回该类的类型信息实例

还可以用Class对象之静态方法forName()获得特定的类型信息。

Class  c1 = Class. forName("MyA");

还可以用某个具体类型获得它的类型信息对象。这称为“类标记”

Class c2 = MyA.class;

class c3 = int.class;

类型信息不仅可用于类,还可以用于数组和接口,甚至是原生类型

 

类型信息的用处:

1)判断某个对象是否为某类型所创建

if(x.getClass().getName() ...) ...   // 通过类名来判断

if(x.getClass == MyA.class) ...   // 通过类型信息的实唯一性

2)根据一个字符串去创建一个类的对象

Object  m = Class. forName("MyA").newInstance();

newInstance()是用未知类型创建对象的好方法

3)执行一个动态类中的动态方法

假如,曾有一个类是这样的:

class AAA{

public int myadd(int x, int y){

return x + y;

}

}

在编译时,不用知道这个类,就可在写出如下的代码来:

Class c1 = Class.forName("AAA");

Object obj = c1.newInstance();    //创建了动态类的对象实例

 

Class[] para_type = {Integer.TYPE, Integer.TYPE};

Method m = c1.getMethod("myadd", para_type);  //在该类信息中找到需要调用的方法

 

Object[] para = {new Integer(5), new Integer(9)};  //准备实参

Integer i = (Integer)m.invoke(obj,para);   //调用方法

System.out.println(i);

8.java中的垃圾回收

java语言,较之c语言的较大改进之一就是:它提供了垃圾回收机制。我们不需要自己来管理内存。程序员只负责分配对象,在不负责清理不再使用的对象。但也会存在内存泄漏的问题。

java中的垃圾回收,即gc

怎样发现某个对象,不再使用?较多地使用“引用遍历法”。

java的垃圾回收,一般分为3个阶段的动作:标记,清除,压缩

jvm只在内存紧张的时候,才去做收垃圾的工作。

System.gc()方法,可以催促jvm去回收空间(不能保证一定会执行回收动作)

对象被回收的时候,会去调用protected void finalize()方法

每个jvm的不同实现,都可能会采用独特的垃圾回收办法。并没有哪一种垃圾回收办法具有绝对的优势。这与应用中怎样创建和使用对象有很大的关系。

一般可以通过调整jvm的参数,来优化垃圾回收可参看jvm的帮助。

原创粉丝点击