StringBuffer 和StringBuilder中的两个函数:
//int indexOf(String str) :返回当前StringBuffer对象中,第一个满足str子串的位置。 //int indexOf(String str, int fromIndex) :从fromIndex开始查找,返回第一个满足str子串的位置。 StringBuffer sb = new StringBuffer("This is a StringBuffer!"); System.out.println("sb.indexOf(\"is\") = " + sb.indexOf("is")); //2 System.out.println("sb.indexOf(\"is\", 4) = " + sb.indexOf("is", 4)); //5 System.out.println("sb.indexOf(\"is\", 4) = " + sb.indexOf("is", 7)); // -1 //StringBuffer insert(int offset, String str) //在当前StringBuffer对象中插入一个元素,在索引号offset处插入相应的值。 StringBuffer sf = new StringBuffer("..{..}) public class ESBYSYSInquiryMachineInfoSrvRequest {"); int classIdx = sf.indexOf("public class "); if(classIdx > 0){ sf.insert(sf.indexOf("{", classIdx), " implements java.io.Serializable"); } System.out.println(sf.toString()); //..{..}) public class ESBYSYSInquiryMachineInfoSrvRequest implements java.io.Serializable{
2.保留2位小数:
import java.text.DecimalFormat; DecimalFormat df=new DecimalFormat("0.00"); Double x = 83.3333333333; x=Double.parseDouble(df.format(x));
3.group by 和 order by
ORDER BY 用于对数据按指定的列和方法排序。 select * from syscolumns order by id asc, colorder desc; 指示查询出的结果 按 id 正序排列, colOrder 逆序排列。 GROUP BY 用于汇总统计。 HAVING 用途和 WHERE类似,但用于对 GROUP BY 的结果进行过滤。 select id, count(id) from syscolumns group by id; 这条语句以 id 进行汇总,统计出每个不同的 id 出现的个数。 select id, count(id) from syscolumns group by id having count(1) > 10; 这条语句以 id 进行汇总,统计出每个不同的 id 出现的个数,但 having 后的条件指定了只显示 count(id) 大于 10 的数据。。 先Group by ,后 Order by
4.日期
获取当前时间:
1. SimpleDateFormat tempDate = new SimpleDateFormat("yyyy-MM-dd" + " " + "hh:mm:ss"); String datetime = tempDate.format(new java.util.Date()); 2. Calendar now=Calendar.getInstance(); String time=now.get(Calendar.YEAR)+"-"+(now.get(Calendar.MONTH)+1)+"-"+now.get(Calendar.DAY_OF_MONTH)+" "+now.get(Calendar.HOUR_OF_DAY)+":"+now.get(Calendar.MINUTE)+":"+now.get(Calendar.SECOND); 3.Date curDate= new Date(System.currentTimeMillis());
- SimpleDateFormat format = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ); //24小时制
- SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");//12小时制
a.获取年、月、日:
String year=String.valueOf(c.get(Calendar.YEAR)); String month=String.valueOf(c.get(Calendar.MONTH)+1); String day=String.valueOf(c.get(Calendar.DAY_OF_MONTH));
b.Calendar和Date的转化
(1) Calendar转化为Date
Calendar cal=Calendar.getInstance(); Date date=cal.getTime();
(2) Date转化为Calendar
Date date=new Date(); Calendar cal=Calendar.getInstance(); cal.setTime(date);
c.计算一年中的第几星期
(1)计算某一天是一年中的第几星期
Calendar cal=Calendar.getInstance(); cal.set(Calendar.YEAR, 2006); cal.set(Calendar.MONTH,1); cal.set(Calendar.DAY_OF_MONTH, 3); int weekno=cal.get(Calendar.WEEK_OF_YEAR);
(2)计算一年中的第几星期是几号
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd"); Calendar cal=Calendar.getInstance(); cal.set(Calendar.YEAR, 2006); cal.set(Calendar.WEEK_OF_YEAR, 1); cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY); System.out.println(df.format(cal.getTime())); 输出: 2006-01-02
d:
1天内(注意为add ):
Calendar c=Calendar.getInstance(); c.add(Calendar.DAY_OF_MONTH, -1); //得到前一天的时间 startDateStr=sf.format(c.getTime()); endDateStr=sf.format(java.util.Calendar.getInstance().getTime()); 推荐使用这种方法获取当前时间,不推荐使用new Date()
3天内:
Calendar c=Calendar.getInstance(); c.add(Calendar.DAY_OF_MONTH, -3); //得到前3天的时间 startDateStr=sf.format(c.getTime());
近1月:
Calendar c=Calendar.getInstance(); c.add(Calendar.MONTH, -1); startDateStr=sf.format(c.getTime());
到当前时间的前几年的时间:
Calendar c = Calendar.getInstance(); c.add(Calendar.YEAR, -5);//得到前5年 SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String mDateTime=formatter.format(c.getTime()); String strStart=mDateTime.substring(0, 16);//2002-10-24 09:30
本月(注意为set ):
Calendar c=Calendar.getInstance(); c.set(Calendar.DATE,1); //把日期设为当月第一天 startDateStr=sf.format(c.getTime());
上月:
Calendar c2=Calendar.getInstance(); c2.add(Calendar.MONTH,-1); c2.set(Calendar.DATE,1); startDateStr=sf.format(c2.getTime());
5.文本域input的不可编辑属性 disabled 和 readonly 区别
disable 属性 -- 表示已经失效的输入域
readonly 属性 -- 表示只读(只能看到,不能修改)的输入域(框)
<input type="checkbox" value="2" name="fav" disabled="disabled" /> <input type="text" name="notinput" readonly="readonly" />
/**是否闰年 */ public boolean isLeapYear(int year) { return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0); }
具体日期操作:
http://www.360doc.com/content/09/0820/17/236102_5085810.shtml
可将选中的代码拖动到QQ聊天窗口中复制
6.File协议
表示本地文件传输协议,File协议主要用于访问本地计算机中的文件 ,就如同在Windows资源管理器中打开文件一样。
应用:要使用File协议,基本的格式如下:file:///文件路径,比如要打开F:盘flash文件夹中的1.swf文件,那么可以在资源管理器或IE地址栏中键入:file:///f:/flash/1.swf并回车。
3个斜杠代表本地
8.substring(int beginIndex, int endIndex)
该子字符串从指定的 beginIndex 处开始,直到索引 endIndex - 1 处的字符。因此,该子字符串的长度为 endIndex-beginIndex。
示例:
"hamburger".substring(4, 8) returns "urge"
"smiles".substring(1, 5) returns "mile "
参数:
beginIndex - 起始索引(包括)。
endIndex - 结束索引(不包括) 。
9.什么时候用Thread.getContextClassLoader()
需要动态加载很多类和资源的时候 .
通常当你需要动态加载资源的时候 , 你至少有三个 ClassLoader 可以选择 :
² 系统类加载器或叫作应用类加载器 (system classloader or application classloader)
² 当前类加载器
² 当前线程类加载器
10.instanceof 运算符
指出对象是否是特定类的一个实例。
String s = "I AM an Object!"; boolean isObject = s instanceof Object; public double calculate(Bill bill) { if (bill instanceof PhoneBill) { //计算电话账单 } }
11、java环境配置(都放下面):
CLASSPATH .;%JAVA_HOME%\lib
JAVA_HOME C:\Program Files\Java\jdk1.6.0_22
Path .;%JAVA_HOME%\bin
13.JDK1.5的新特性
“JDK1.5”(开发代号猛虎)的一个重要主题就是通过新增一些特性来简化开发 ,这些特性包括泛型,for-each循环,自动装包/拆包,枚举,可变参数, 静态导入 。使用这些特性有助于我们编写更加清晰,精悍,安全的代码。
自动装包/拆包
自动装包/拆包大大方便了基本类型数据和它们包装类地使用。
自动装包:基本类型自动转为包装类.(int >> Integer)
自动拆包:包装类自动转为基本类型.(Integer >> int)
在JDK1.5之前,我们总是对集合不能存放基本类型而耿耿于怀,现在自动转换机制解决了我们的问题。
在实际开发过程中,我们经常会遇到需要使用对象,而不是内置数据类型的情形。为了解决这个问题,Java语言为每一个内置数据类型提供了对应的包装类。
所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类Number的子类。
这里Integer先自动转换为int进行加法运算,然后int再次转换为Integer.
int a = 3; Collection c = new ArrayList(); c.add(a);//自动转换成Integer. Integer b = new Integer(2); c.add(b + 2);
枚举:
public enum Color { Red, White, Blue }
然后可以这样来使用Color myColor = Color.Red.
枚举类型还提供了两个有用的静态方法values()和valueOf(). 我们可以很方便地使用它们,例如
for (Color c : Color.values()) System.out.println(c);
带构造函数的枚举:
public enum Color { RED("红色"),BLUE("蓝色"),GREEN("绿色"); private final String name; public String getName() { return name; } private Color(String name){ this.name=name; } }
System.out.println("Color.RED.name():"+Color.RED.name()); //RED System.out.println("Color.RED.toString():"+Color.RED.toString()); //RED System.out.println(Color.RED.getName()); //红色
Color.RED.name()
Color.RED.toString(); 得到的都是RED
而且这些枚举值都是public static final的,也就是我们经常所定义的常量,因此枚举类中的枚举值最好全部大写 。
2、即然枚举类是class,当然在枚举类型中有构造器,方法和数据域。但是,枚举类的构造器有很大的不同:
(1) 构造函数只是在构造枚举值的时候被调用。
(2) 枚举构造函数只能私有private ,绝对不允许有public构造器。这样可以保证外部代码无法新构造枚举类的实例。因为我们知道枚举值是public static final的常量而已 但枚举类的方法和数据域可以允许外部访问。
/** * * 服务器类型 * */ public enum ServerType { JBoss("server/default/deploy","client,common"), WebLogic("",""), GlassFish("",""); private String deployPath; private String libClassPath; private ServerType(String deployPath, String libClassPath){ this.deployPath = deployPath; this.libClassPath = libClassPath; } public String getDeployPath(){ return this.deployPath; } public String getLibClassPath(){ return this.libClassPath; } }
ServerType serverType = ServerType.JBoss;
String deployPath = serverType.getDeployPath();
String libClassPath = serverType.getLibClassPath();
可变参数:
当不能确定一个方法的入口参数的个数时,以往版本的Java中,通常的做法是将多个参数放在一个数组或者对象集合中作为参数来传递,1.5版本以前的写法是:
int sum(Integer[] numbers) { int nSum = 0; for(int i: numbers) nSum += i; return nSum; }
在别处调用该方法
sum(new Integer[] {12,13,20});
而在1.5版本中可以写为:
public static int sum(Integer... number){ int nSum=0; for(int i : number){ nSum+=i; } return nSum; }
在别处调用该方法
System.out.println("sum():"+sum(12,13,14)); System.out.println("sum():"+sum(12,13));
静态导入:
要使用静态成员(方法和变量)我们必须给出提供这个方法的类。使用静态导入可以使被导入类的所有静态变量和静态方法在当前类直接可见,使用这些静态成员无需再给出他们的类名。
不过,过度使用这个特性也会一定程度上降低代码地可读性。
import static java.lang.Math.*; ……. r = sin(PI * 2); //无需再写r = Math.sin(Math.PI);
14.o1.CompareTo(o2);
整形间比较会返回1、-1、0
如:
public static void main(String[] args) { //Integer num1; //num1 = new Integer("24"); //Integer num2; //num2 = new Integer("34"); Integer num2=12; //不可使用 int num2=12;因compareTo(T t)中的T是类,所以必须用包装类 Integer num1=11; System.out.println(num2.compareTo(num1)); //1 System.out.println("------------------"); System.out.println(num1.compareTo(num2)); //-1 }
字符串间比较:
"abcd" .compareTo( "adef" )== -2
"abc" .compareTo( "abcdef" )== -3
"abc" .compareTo( "abc" ) == 0
简单 字符串的排序 。(例如使用 compareTo 进行姓名的排序)
//需要进行排序的字符串 String[] array = new String[] { "lilei", "libai", "james", "poly", "wobfei" }; //使用简单的循环排序 for (int i = 0; i < array.length ; i++) { for (int j = i + 1; j < array.length-1; j++) { if (array[i].compareTo(array[j]) > 0) { String temp = array[i]; array[i] = array[j]; array[j] = temp; } } }
使用上面针对 String 的排序以后,字符串的内容将会是:
james libai lilei poly wobfei
该例子来源(稍作了修改):http://wobfei.iteye.com/blog/743123
15.编码习惯
add、saveAdd
edit、saveEdit
16、Math.round();
Math.round(m) = (int)Math.floor(a + 0.5f)
Math.ceil(x):比x大的最小值。
Math.round(x):四舍五入。
Math.floor(x):比x小的最大值。
jdk说得很明白了,
-11.5+0.5=-11 Math.floor(-11)=-11
-11.3+0.5=-10.8 Math.floor(-10.8)= -11
-11.8+0.5=-11.3 Math.floor(-11.3)= -12
17、重写
关于重写,遵循以下的规则:
(1)重写方法必须和被重写方法具有相同的参数列表, 返回类型必须和被重写方法的返回类型相同或者是返回类型的子类型 。
(2)重写方法的访问控制修饰符不能比被重写方法更严格(比如一个在父类中声明为public的方法重写成一个protected的方法)。
18.
class Test { void test(int i) { System.out.println("I am an int." + i); } void test(String s) { System.out.println("I am a string."); } public static void main(String args[]) { Test t = new Test(); char ch = 'y'; t.test(ch); } //结果为:I am an int.121 }
19.JDBC的主要任务是什么?(三个)
1、建立与数据库的连接。
2、向数据库发起查询请求。
3、处理数据库返回结果。
20.TreeSet的构造函数
TreeSet();
TreeSet(Collection c);//构造一个包含指定 collection 元素的新 TreeSet,它按照其元素的自然顺序 进行排序。
TreeSet(Comparator comparator);//构造一个新的空 TreeSet,它根据指定比较器进行排序。
public class NameComparator implements Comparator<Name>{ public int compare(Name n1,Name n2){ if(n1.getName().compareTo(n2.getName())>0) return -1; if(n1.getName().compareTo(n2.getName())<0) return 1; return 0; } public static void main(String[] args) { Set<Name> set = new TreeSet<Name>(new NameComparator()); Name n1 = new Name("ray"); Name n2 = new Name("tom"); Name n3 = new Name("jame"); set.add(n1); set.add(n2); set.add(n3); Iterator it = set.iterator(); while(it.hasNext()){ Name s = (Name)it.next(); System.out.print(s.getName()+","); } System.out.println("一共有对象:"+set.size()+"个"); } }//打印结果是:tom,ray,jame,一共有对象:3个
客户端排序时因为java.util.Comparator<Type>接口提供了具体的排序方式,<Type>指定了被比较对象的类型,Comparator有个compare(Type x,Type y)的方法,用于比较两个对象的大小。
21.Object中的hashcode()和equals()
在Java中任何一个对象都具备equals(Object obj)和hashcode()这两个方法,因为他们是在Object类中定义的。
equals(Object obj)方法用来判断两个对象是否“相同”,如果“相同”则返回true,否则返回false。
hashcode()方法返回一个int数,在Object类中的默认实现是“将该对象的内部地址转换成一个整数返回”。
接下来有两个个关于这两个方法的重要规范(我只是抽取了最重要的两个,其实不止两个):
规范1: 若重写equals(Object obj)方法,有必要重写hashcode()方法,确保通过equals(Object obj)方法判断结果为true的两个对象具备相等的hashcode()返回值。说得简单点就是:“如果两个对象相同,那么他们的hashcode应该 相等”。不过请注意:这个只是规范,如果你非要写一个类让equals(Object obj)返回true而hashcode()返回两个不相等的值,编译和运行都是不会报错的。不过这样违反了Java规范,程序也就埋下了BUG。
规范2: 如果equals(Object obj)返回false,即两个对象“不相同”,并不要求对这两个对象调用hashcode()方法得到两个不相同的数。说的简单点就是:“如果两个对象不相同,他们的hashcode可能相同”。
根据这两个规范,可以得到如下推论:
1、如果两个对象equals,Java运行时环境会认为他们的hashcode一定相等 。
2、如果两个对象不equals,他们的hashcode有可能 相等。
3、如果两个对象hashcode相等,他们不一定 equals。
4、如果两个对象hashcode不相等,他们一定不 equals。
http://www.iteye.com/topic/800929
22.序列化
Serializable接口没有需要实现的方法,
implements Serializable只是为了标注该对象是可被序列化的,
然后 使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象 ,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
实现序列化(保存到一个文件)的步骤
a)Make a FileOutputStream
FileOutputStream fs = new FileOutputStream("foo.ser");
b)Make a ObjectOutputStream
ObjectOutputStream os = new ObjectOutputStream(fs);
c)write the object
os.writeObject(myObject1);
o s.writeObject(myObject2);
os.writeObject(myObject3);
d) close the ObjectOutputStream
os.close();
23、计划任务:
java.util.Timer
timer.schedule(...);
http://www.blogjava.net/georgehill/archive/2005/06/09/5793.aspx
http://www.klstudio.com/post/187.html
24.Split
在java.lang包中有String.split()方法,返回是一个数组
我在应用中用到一些,给大家总结一下,仅供大家参考:
1、如果用“.”作为分隔的话,必须是如下写法:String.split("\\."),这样才能正确的分隔开,不能用String.split(".");
2、如果用“|”作为分隔的话,必须是如下写法:String.split("\\|"),这样才能正确的分隔开,不能用String.split("|");
“.”和“|”都是转义字符,必须得加"\\";
3、如果在一个字符串中有多个分隔符,可以用“|”作为连字符,比如:“acount=? and uu =? or n=?”,把三个都分隔出来,可以用String.split("and|or");
java转义字符
\":双引号
\':单引号
\\:反斜线
25.作用范围:
this.context.setAttribute(MyConstants.CONTINENTS_KEY, continentlist);
public static final String CONTINENTS_KEY="CONTINENTS";
jsp页面中可以直接使用 CONTINENTS(${CONTINENTS }) ,而无需context.getAttribute("");
<body> <% request.setAttribute("name","xiaoming") ;%> <input type="text" value="${name}"/> </body>
26.数组转为list
List stooges = Arrays.asList("Larry", "Moe", "Curly");
此时stooges中有有三个元素。注意:此时的list不能进行add操作,否则会报 “java.lang.UnsupportedOperationException”,Arrays.asList()返回的是List,而且是一个定长的List,所以不能转换为ArrayList,只能转换为AbstractList
原因在于asList()方法返回的是某个数组的列表形式,返回的列表只是数组的另一个视图,而数组本身并没有消失,对列表的任何操作最终都反映在数组上. 所以不支持remove,add方法的
String[] arr = {"1", "2"}; List list = Arrays.asList(arr);
27、使用ResourceBundle读取properties文件
有时候有些简单的配置文件可以没必要使用xml,其实ResourceBundle类就已经做的很好的。它甚至可以搜索到classpath里的jar文件中一些properties文件。
例如在jar文件中的根目录放置一个文件:test.properties,然后只要这个jar文件在classpath里。就可以使用这样的语句来获得一些属性:
ResourceBundle rb = ResourceBundle.getBundle("test"); String s = rb.getString("FirstKey"); System.out.println(s);
28、HttpClient学习
public class TestHttpClient { public static void main(String[] args) { String url = "http://images.gta-travel.com/HH/Images/HX/HKGA/HKGA-REG-1.jpg|http://images.gta-travel.com/HH/Images/HX/HKGA/HKGA-REG-2.jpg"; String[] urlArr = url.split("\\|"); String fileName = "D:\\httpClient"; HttpClient client = new HttpClient(); GetMethod method = new GetMethod(urlArr[1]); // 使用 GET 方法 ,如果服务器需要通过 HTTPS 连接,那只需要将下面 URL 中的 http 换成 https FileOutputStream output = null; try { client.executeMethod(method); File showFile = new File(fileName + ".jpg"); output = new FileOutputStream(showFile); output.write(method.getResponseBody()); //method.getResponseBody()为byte[]类型 output.flush(); } catch (HttpException e) { } catch (IOException e) { } finally { if (output != null) { try { output.close(); output = null; } catch (IOException e) { } } } } }
http://www.blogjava.net/Alpha/archive/2007/01/22/95216.html
29、栈、堆
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制.
2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中。)
3. 堆:存放所有new出来的对象。
4. 静态域 :存放静态成员(static定义的)
5. 常量池 :存放字符串常量和基本类型常量(public static final)。
6. 非RAM存储:硬盘等永久存储空间
这里我们主要关心栈,堆和常量池,对于 栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定 ,具有很大的灵活性。
对于字符串:其对象的引用都是存储在栈中的,如果是 编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中 。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。
new String("China");
对于通过new产生一个字符串(假设为”china”)时,会先去常量池中查找是否已经有了”china”对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此”china”对象的拷贝对象。这也就是有道面试题:String s = new String(“xyz”);产生几个对象?一个或两个,如果常量池中原来没有”xyz”,就是两个。
对于成员变量和局部变量:成员变量就是方法外部,类的内部定义的变量;局部变量就是方法或语句块内部定义的变量。局部变量必须初始化。
形式参数是局部变量,局部变量的数据存在于栈内存中 。栈内存中的局部变量随着方法的消失而消失。
成员变量存储在堆中的对象里面 ,由垃圾回收器负责回收
http://www.iteye.com/topic/634530
30.try-catch
public class Test { public static void main(String[] args) { System.out.println("return value of getValue(): " + getValue()); } public static int getValue() { int i = 1; try { return i; } finally { System.out.println("i : finally"); ++i; } } }
public static boolean get() { try { return false; } finally { return true; } }
在try中的return真正返回之前 ,会将false保存到一个临时变量(假设为var)中 ,然后执行finally,在执行finally子句的任何语句之前,会将var中的值取出,如果finally中没有抛出异常或return、break、continue等语句,则在finally执行完后返回var (相当于返回去完成try中return的执行),如果finally中有return,var值会被覆盖 ,返回结果是finllay子句中 return的值,如果是异常或break、continue等则执行相应的操作而不是返回。更详细解释参考JVM规范或《深入理解JAVA虚拟机(第二版)》。
其实相当于值传递
结果:1 true
31、返回一个n位随机数
random.nextInt(n)
返回0~n 间的整数,包括0,不包括n
public static String getRandStr(int n){ Random random = new Random(); String sRand = ""; for (int i = 0; i < n; i++) { String rand = String.valueOf(random.nextInt(10)); sRand += rand; } return sRand; }
getRandStr(4)可返回一个4为数
32、java中的main方法
String args[]保存的是 JAVA运行时传递给所运行类的参数,你这个类需要参数就传,不需要就不传.
public class TestMain{ public static void main(String args[]){ for(int i=0;i<args.length;i++){ System.out.println(args[i]); } } }
接着用java TestMain first second运行
结果:
first
second
args实际上是个变量。它用来存储你用命令后执行.class文件时后面跟的参数。args是可以变的,你可以变为你喜欢的任意标识符。
普通方法其实可以不给,只是你在设计方法的时候要给一个不传参数的方法。
注意:
1、其返回类型应该为void
2、必须为公共方法
a. public static void main()
b. public static void main(String[] string)
c. public static void main(string args)
d. static public int main(String[] args)
e.static void main(String[] args)
33、Map遍历
for(Map.Entry<String, String> entry : map.entrySet()){ System.out.println(entry.getKey()+"--->"+entry.getValue()); }
34、for循环
for语句的格式为:
for (初始化语句; 条件语句; 控制语句)
{
语句1 ;
语句2 ;
....
语句n ;
}
for 语句的执行顺序是:首先执行“初始化语句”;然后测试“条件语句”;若条件成立,则执行语句1到语句n;然后执行“控制”语句;接着再测试条件语句是否成立,如果成立则重复执行以上过程,直至条件不成立时才结束for循环。
35、 Java 内存模型
2.1 Java 内存模型的基本原理
Java 内存模型,由于 Java 被设计为跨平台的语言,在内存管理上,显然也要有一个统一的 模型。系统存在一个主内存 (Main Memory) , Java 中所有变量都储存在主存中,对于所有线程都是共享的。每条线程都有自己的工作内存 (Working Memory) ,工作内存中保存的是主存中某些变量的拷贝,线程对所有变量的操作都是在工作内存中进行,线程之间无法相互直接访问,变量传递均需要通过主存完成。
因为当线程处于不同的cpu中时,它各自的变量保存在各自cpu的寄存器或者高速缓存中,这样回事的变量对于其它线程暂时不可见。
2.2 Volatile 的内存工作原理
Volatile 是保证多个线程之间变量可见性的,也就是说一个线程对变量进行了写操作,另外一个线程能够获取它最新的值。
它的工作原理是,它对写和读都是直接操作工作主存的。(这个可以通过操作字节码看到)
2.3 Synchronized 的内存操作模型 :
Synchronized, 有两层语义,一个是互斥,一个是可见性。在可见性上面,它的工作原理有点不同:当线程进入同步块时,会从主存里面获取最新值,然后当线程离开同步块时,再把变量的值更新到主存。
http://tomyz0223.iteye.com/blog/1001778
36.删除一个文件夹内的所有文件和文件夹
File file = new File(imgPath); if (!file.exists()) return; deleteDirectory(file); public void deleteDirectory(File path) { if( path.exists() ) { File[] files = path.listFiles(); for(int i=0; i<files.length; i++) { if(files[i].isDirectory()) { deleteDirectory(files[i]); } else { files[i].delete(); } } } }
37、关于JSP中的pageContext:
使用pageContext所设定的属性对象,其共享范围限于同一个JSP页面,
使用request所设定的属性对象,其在同一个request处理期间可以共享(包括forward给其它JSP页面),
session对象所设定的属性对象则限于同一个进程作用期间可以共享,
而application对象所设定的属性,则在整个Web应用程序中的JSP页面都可以共享。
38,Final的初始化
1. final修饰的成员变量没有默认值
2. final初始化可以在三个地方
(1)声明的时候初始化
(2)构造函数里初始化
(3)要是没有static修饰的话可以在非静态块里初始化,要是有static修饰的话可以在静态块里初始化
3. 使用final成员前要确保已经初始化,如果没初始化,或者初始化多次,则无法通过编译。
39、一些转换技巧
Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); //map转换list List<HandlerMapping> handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values()); //map判断空 if (!matchingBeans.isEmpty()) //数组转List (interceptors 数组) interceptorList.addAll(Arrays.asList(this.interceptors)); //List转指定对象数组 interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
40、java.lang.Number是所有基础类型的父类
public abstract class Number implements java.io.Serializable { public abstract int intValue(); public abstract long longValue(); public abstract float floatValue(); public abstract double doubleValue(); public byte byteValue() { return (byte)intValue(); } public short shortValue() { return (short)intValue(); } }
public final class Long extends Number implements Comparable<Long> public final class Integer extends Number implements Comparable<Integer>
41、JDK、JRE、JVM
JDK:Java Development ToolKit
Java开发工具包
JRE:Java Runtime Environment
Java运行环境
JVM:Java Virtual Machine
Java虚拟机
JDK是SUN公司发布的用于开发Java程序的工具包
在它的bin目录下有很多工具,常见的包括:javac.exe,java.exe,javadoc.exe等(其中有很多都是用Java编写的)各种版本的IDE工具也是需要使用JDK来完成编译,打包,运行等各种功能的。
JRE顾名思义,java的运行环境
JDK是开发工具,在它的安装目录下包含了JRE目录,其实在安装JDK时(1.4版本以上),有一个安装选项,如果勾上时,在Java的安装目录下会多一个JRE目录,这里的JRE与JDK下的JRE目录基本上是完全一致的,那么为什么需要两个JRE呢?
前面已经提到过,JDK的bin目录下的很多工具都是用Java编写的,使用这些工具的时候也是需要运行环境的,通过这些.exe包装器(这些包装器提供了寻找tools.jar中的一些java类的快捷方法,不需要输入一长串的包名和类名)来使用那些工具时,java会自动寻找父目录下的JRE,所以在这里放置了JRE。
JVM:Java虚拟机,在window下作为动态连接库(jvm.dll)存在,用于解释执行Java字节码。
可以把它理解成是专门用来执行Java程序的一台机器。也就是说JVM提供了Java执行的硬件平台。JVM上执行的代码都存放在.CLASS文件中。JVM只执行字节码文件。
42、finalize()
Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。
这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。
finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
垃圾收集器只知道释放那些由new分配的内存,所以不知道如何释放对象的“特殊”内存。为解决这个问题
Java提供了一个名为finalize()的方法,它的工作原理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象的内存。
所以如果使用finalize(),就可以在垃圾收集期间进行一些重要的清除或清扫工作(如关闭流等操作)。但JVM(Java虚拟机)不保证此方法总被调用。
43、原子操作AtomicInteger
public class AtomicLong extends Number implements Serializable
J2SE 5.0提供了一组atomic class来帮助我们简化同步处理。
基本工作原理是使用了同步synchronized的方法实现了对一个long, integer, 对象的增、减、赋值(更新)操作. 比如对于++运算符, AtomicInteger可以将它持有的integer 能够atomic 地递增。在需要访问两个或两个以上 atomic变量的程序代码(或者是对单一的atomic变量执行两个或两个以上的操作)通常都需要被synchronize以便两者的操作能够被当作是一个atomic的单元。
addAndGet(long delta) //以原子方式将给定值添加到当前值。 getAndSet() : //设置新值,返回旧值. compareAndSet(expectedValue, newValue) : //如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值 //如果更新成功,返回true, 否则返回false //换句话可以这样说: 将原子变量设置为新的值, 但是如果从我上次看到的这个变量之后到现在被其他线程修改了(和我期望看到的值不符), 那么更新失败 /* 单线程下, compareAndSet返回永远为true, * 多线程下, 在与result进行compare时, counter可能被其他线程set了新值, 这时需要重新再取一遍再比较, * 如果还是没有拿到最新的值, 则一直循环下去, 直到拿到最新的那个值 */
为了提高性能,AtomicLong等类在实现同步时,没有用synchronized关键字,而是直接使用了最低层(本地c语言实现代码)来完成的,
因而你是看不到用synchronized关键字的.
比如:AtomicLong类中原子操作方法:
public final boolean compareAndSet(long expect, long update) ;
就是直接使用SUN公司低层本地代码的原子方法(native方法):
public final native boolean compareAndSwapLong(...)来实现的.
44、Object、String类中equals方法的不同
StringBuffer / StringBuilder的equals方法都是继承的Object方法
String类中对equals方法进行了重写
Object类的equals方法的实现:
public boolean equals(Object obj) { return (this == obj); }
Object中的equals就是用==来比较当前对象和传入的参数的。
再看看String的equals实现:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = count; if (n == anotherString.count) { char v1[] = value; char v2[] = anotherString.value; int i = offset; int j = anotherString.offset; while (n-- != 0) { if (v1[i++] != v2[j++]) return false; } return true; } } return false; }
它去比较内容了。
再看StringBuilder,在其源码里没有发现equals方法,那么它就继承了Object的实现,用==来比较传进来的参数。
我们看到equals是个实例方法(非static),实例方法是可以被子类重写而去实现自己想要的行为的,因此,不能轻易的说equals就是比较内容的,其行为是特定于实现的。但==确实是比较地址的。因为java中不支持(至少现在不支持)运算符重载,我们不能改变==的含义,其行为是固定死的。
记得下次不要说“==比较地址,equals比较内容”这样的话了,如果要说,也在前面加上特定的条件,如“如果比较String”,勿断章取义。
45、不借助中间变量交换元素
a = a + b b = a - b a = a - b
46.UUID
UUID(Universally Unique Identifier)
全局唯一标识符
是指在一台机器上生成的数字,是1.5中新增的一个类,在java.util下,用它可以产生一个号称全球唯一的ID
按照开放软件基金会(OSF)制定的标准计算,用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。
由以下几部分的组合:当前日期和时间(UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同),时钟序列,全局唯一的IEEE机器识别号(如果有网卡,从网卡获得,没有网卡以其他方式获得),UUID的唯一缺陷在于生成的结果串会比较长。
JDK1.5
如果使用的JDK1.5的话,那么生成UUID变成了一件简单的事,以为JDK实现了UUID:
java.util.UUID,直接调用即可.
String s = UUID.randomUUID().toString();
UUID是由一个十六位的数字组成,表现出来的形式例如
550E8400-E29B-11D4-A716-446655440000
47、获取随机数
法1:
int num = getRandom(1000); public static int getRandom(int num) { return (int) Math.round(Math.random() * num); }
API:
double java.lang.Math.random()
//Returns a double value greater than or equal to 0.0 and less than 1.0
long java.lang.Math.round(double a)
法2:
Random random = new Random(); int num = random.nextInt(50);
API:
int java.util.Random.nextInt(int n)
//Returns a int value between 0 (inclusive) and the specified value (exclusive),
公共方法:
public static final String allChar = "023456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ"; public static final String numberChar = "023456789"; /* * 获取随机字符串 */ public static String generateString(int length){ //参数为返回随机数的长度 StringBuffer sb = new StringBuffer(); Random random = new Random(); for (int i = 0; i < length; i++) { sb.append(allChar.charAt(random.nextInt(allChar.length()))); } return sb.toString(); } public static String generateNumber(int length){ //参数为返回随机数的长度 StringBuffer sb = new StringBuffer(); Random random = new Random(); for (int i = 0; i < length; i++) { sb.append(numberChar.charAt(random.nextInt(numberChar.length()))); } return sb.toString(); }
48、request.getParameterMap()
在servlet中GET请求可以通过HttpServletRequest的getRequestURL方法和getQueryString()得到完整的请求路径和请求所有参数列表,
POST的需要getParameterMap()方法遍历得到,
不论GET或POST都可以通过getRequestURL+getParameterMap()来得到请求完整路径
request.getParameterMap()的返回类型是Map类型的对象,也就是符合key-value的对应关系,但这里要注
意的是,value的类型是String[],而不是String.
得到jsp页面提交的参数很容易,但通过它可以将request中的参数和值变成一个map,以下是将得到的参数和值
打印出来,形成的map结构:map(key,value[]),即:key是String型,value是String型数组。
例如:request中的参数t1=1&t1=2&t2=3
形成的map结构:
key=t1;value[0]=1,value[1]=2
key=t2;value[0]=3
如果直接用map.get("t1"),得到的将是:Ljava.lang.String; value只所以是数组形式,就是防止参数名有相同的
情况。
public class ParamsUitl { public static Map<String, String> getParamsMap(HttpServletRequest request) { Map<String,String> params = new HashMap<String,String>(); Map requestParams = request.getParameterMap(); for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); String[] values = (String[]) requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } valueStr = new String(valueStr); params.put(name, valueStr); } return params; } }
易错题:
1、
int j = 0; j = j++; System.out.println(j);
没见过此题的人,大部分人可能得到的结果是:1。 然而,运行的结果会令您彻底失望。这是什么原因呢?原来Java编译器处理后缀++或--时是这么处理的:java的编译器在遇到j++和j- -的时候会重新为变量运算分配一块内存空间,以存放原始的值,而在完成了赋值运算之后,将这块内存释放掉。即JAVA先将j的值保存到临时内存空间中,然 后处理++,即原来的j加1,此时原来的j变成1,然后再执行赋值,将内存空间中所存放的原来的值赋回给j,所以j仍然是0。C#和Java的结果是一样 的。
相反,C/C++不是这么处理的:C中是通过寄存器作中转先把j的值赋给它本身,再执行++的操作,这样结果就是1了。
2、
String a = "abc"; String b = "abc"; System.out.println("====>"+ a==b ); //"+"的优先级比"=="高,实际比较的是"====>abc"与abc false System.out.println("====>"+ (a==b) ); //true
3、一眼能说出它的结果
public class MainTest { public static void main(String[] args) { String s = null; s = s+"word"; System.out.println("hello " +s); } }
结果:hello nullword
String s = null; //s = s+"word"; System.out.println("hello " +s); //结果:hello null
抽象类中可以有抽象方法和非抽象方法 !
构造方法可以被重载,但不可以被重写
数组没有 length() 这个方法,有 length 的属性。 String 有有 length() 这个方法。
Scanner scanner = new Scanner(System.in); String temp = scanner.nextLine(); System.out.println("temp=="+temp); // 输入。。。
new String(name.getBytes("iso-8859-1"),"utf-8");
其他:
java类成员变量在没有赋值的时候会赋以默认值,其它局部变量是不能够享受这种待遇的。