1.自动类型转换:目标类型大于源类型(double类型a = int类型b)
2.当使用逻辑运算符时,我们会遇到一种很有趣的“短路”现象。
譬如:( one > two )&& ( one < three )中,如果能确定左边 one > two 运行结果为 false , 则系统就认为已经没有必要执行右侧的one < three 啦。
同理,在( one < two )||(one > three ) 中,如果能确定左边表达式的运行结果为true , 则系统也同样会认为已经没有必要再进行右侧的 one < three 的执行啦!
3.int --> String
String str = num + "";
String str = String.valueOf(num);
String str = Integer.toString(num);
String-->int
int i = Integer.parseInt(str); 或 i = Integer.parseInt(str,[intradix]);
int i = Integer.valueOf(str).intValue();
4.Arrays.sort(hobbys); //排序
Arrays.toString(hobbys); //字符串输出
5.
String[][]names={{"tom","jack","mike"},{"zhangsan","lisi","wangwu"}};
for (int j = 0; j < names[i].length; j++) {
System.out.println(names[i][j]);
}
6.局部变量必须赋初始值,成员变量可不赋初始值。
当成员变量和局部变量重名时,局部变量优先。
7.程序运行时静态初始化块最先被执行,然后执行普通初始化块,最后才执行构造方法。由于静态初始化块只在类加载时执行一次,所以当再次创建对象一个对象时并不会执行静态初始化块。
8.内部类的主要作用如下:
内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类
内部类的方法可以直接访问外部类的所有数据,包括私有的数据
内部类所实现的功能使用外部类同样可以实现,只是有时使用内部类更方便
内部类可分为以下几种:
成员内部类
静态内部类
方法内部类
匿名内部类
a.成员内部类:
外部类不能直接访问内部类的方法,需要通过外部类的对象创建内部类的对象,调用内部类的方法,如:
Outer out = new Outer();
Inner in = out.new Inner();
如果外部类和内部类具有相同的成员变量或方法,内部类默认访问自己的成员变量或方法,如果要访问外部类的成员变量,可以使用 this关键字:Outer.this.name
b.静态内部类:
内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 访问,如new Outer().age;
如果外部类的静态成员与内部类的成员同名,访问外部类的静态成员:外部类名.静态成员,如:Outer.name;
如果不同名,直接使用成员名访问:name;
创建静态内部类对象:Inner in = new Inner();
c.方法内部类:在外部类的方法中定义的类,因为在外部类的方法以外不能访问,因此无权限修饰符和static。
使用:在外部类的方法内定义一个类,然后在该方法内对内部类实例化,并调用内部类的方法,实例化一个外部类,该实例化对象调用外部类的方法,如:
public class Outer{
public void show(){
class Inner{
public void msg(){}
}
Inner in = new Inner();
in.msg();
}
public static void main(String[] args){
Outer outer = new Outer();
outer.show();
}
}
9.创建一个子类对象的执行顺序:执行父类的属性初始化-->执行父类的构造方法-->执行子类的属性初始化-->执行子类的构造方法
使用 final 修饰属性,必须初始化,既可以在声明时,也可在构造方法中
子类的构造方法默认调用父类的无参构造方法:隐式super调用
10.Object中的 equals() 方法,默认比较对象的引用是否指向同一块内存地址,若要比较内容,需要重写equals()方法;
== 比较引用对象时,比较的是内存地址
不重写toString() 方法,默认为对象地址
11.多态:
父类对象可以指向本类和子类的引用,如:
Animal animal = new Animal();
Animal dog = new Dog();
dog只能调用子类继承的方法,不能调用子类独有的方法。
引用类型转换:向上类型转换为小到大,自动转换;向下相反,需强转,有风险,如把壶里的水倒入杯子中;避免风险,使用instanceof运算符,如:
Dog dog = new Dog();
Animal animal = dog;
if(animal instanceof Dog){
Dog dog2 = animal;
}else{
System.out.println("类型转换失败");
}
12.抽象类不可以实例化,但可使用引用,如:
TelPhone tel1 = new CellPhone();
TelPhone tel2 = new SmartPhone();
TelPhone 为抽象父类,CellPhone和SmartPhone为实现类
同样的,接口的引用可以指向实现的对象,如:
Phone phone = new PhoneImpl();
使用匿名内部类实现接口:
方法一:
Phone phone = new Phone(){
@Override
public void call() {
System.out.println("使用匿名内部类实现接口");
}
};
phone.call();
方法二:
new Phone(){
@Override
public void call() {
System.out.println("使用匿名内部类实现接口2");
}
}.call();
//Phone 为接口
抽象类中的抽象方法(其前有abstract修饰)不能用private、static、synchronized、native访问修饰符修饰,接口中方法除以上外还有protected不可以修饰,即接口中方法只可用public和默认修饰。
13.Throwable类为Error类和Exception类的父类,其中Error为程序终结者,比如VirtualMachineError(虚拟机错误)和ThreadDeath(线程死锁),一般不讨论。Exception类又分为运行时异常RuntimeException(JVM运行程序时自动抛出和捕获,为非检查异常)和检查异常。
RuntimeException:NullPointerException(空指针)、ArrayIndexOutOfBoundsException(数组下标越界)、ClassCastException(类型转换异常)、ArithmeticException(算术异常)等
检查异常:IOException、SQLException等,需要手动捕获并处理
自定义异常类:
public class DrunkException extends Exception{
public DrunkException(){
}
public DrunkException(String message){
super(message);
}
}
将自定义异常类包装成运行时异常类:
public void test1() throws DrunkException{
throw new DrunkException("开车别喝酒");
}
public void test2(){
try {
test1();
} catch (DrunkException e) {
RuntimeException rte = new RuntimeException("hhhhhhh");
rte.initCause(e);
throw rte;
}
}
其中catch块中也可以使用:
catch (DrunkException e) {
RuntimeException rte = new RuntimeException(e);
throw rte;
}
异常经验:尽量使用finally去释放资源;在多个catch块后加上Exception,避免漏掉异常;
14.字符串
正如前所说,==比较内存地址。
String a = "aaa";在堆内存中开辟空间存放“aaa”这个对象,a存放的是指向内存中该对象的一个引用。此时,若String b ="aaa";,首先会去内存中寻找有没有"aaa"这个对象,因为内存中已有该对象,因此b存放的引用指向内存中该对象,此时,a和b的引用均指向同一块内存地址,所以,a==b 返回true。
String a = new String("aaa"); String b = new String("aaa");使用new关键字是每次都在内存中创建一个新对象,就算内容相同,也是不同的对象,a==b返回false,若比较内容,使用equals()方法,即 a.equals(b)返回true。
String a = "aaa";
a = "bbb" + a;此时相当于又在内存中创建了一个新的字符串对象"bbbaaa",而a指向了这个新的对象。
字符串对象在内存中一经创建就无法修改,若要修改,使用StringBuffer对象。
若字符串中不包含某个字符或者子字符串,则indexOf()方法返回-1,可用于包含的判断。
toCharArray(),将字符串转换成字符存在数组里,例程:
for (char i : s.toCharArray()){
//获取每个字符,判断是否是字符a
if (i == 'a') {
// 累加统计次数
num++;
}
}
System.out.println("字符a出现的次数:" + num);
StringBuilder线程不安全,性能较高,因此不考虑线程时,优先考虑;
StringBuffer实现了线程安全
在需要频繁对字符串进行修改操作时使用 StringBuilder 的效率比 String要高
15.基本类型:byte short int long float double charboolean
包装类:Byte Short Integer Long Float Double Character Boolean
int a = 2;
Integer b = new Integer(a);//手动装箱
Integer c = a;//自动装箱
Double d = new Double(20.5);
double e = d.doubleValue();//手动拆箱
double f = d; //自动拆箱
基本类型转换为字符串有三种方法:
1. 使用包装类的 toString() 方法:String a = Double.toString(20.5);
2. 使用String类的 valueOf() 方法:String a = String.valueOf(20.5);
3. 用一个空字符串加上基本类型,得到的就是基本类型数据对应的字符串:
double a = 20.5 + "";
字符串转换成基本类型有两种方法:
1. 调用包装类的 parseXxx 静态方法:double b =Double.parseDouble("20.5");
2. 调用包装类的 valueOf() 方法转换为基本类型的包装类,会自动拆箱:double b =Double.valueOf("20.5");
16. 将日期转换为指定格式文本:
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss");
String now = sdf.format(date);
将文本转换为指定格式日期:
String d = "2014-6-1 21:05:36";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss");
Date date = sdf.parse(d);
注意:使用parse方法可能会出现ParseException,需要做异常处理。
使用Calendar对象:
Calendar c = Calendar.getInstance();
Date date = c.getTime();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss");
String now = sdf.format(date);
Math 类举例:
int x = (int)(Math.random() * 10);
17.集合
java集合分为两类:Collection和Map。Collection有三个子接口:List(有序可重复)、Queue和Set(无序不可重复),其中List的实现类为ArrayList和LinkedList,LinkedList也是Queue的实现类;Set的实现类为HashSet。Map的实现类为HashMap。
ArrayList的两种add方法:
list.add("aa");
list.add(0,"bb");//添加到指定位置,此时bb会在0的位置,将原位于0位的aa挤到1位,需要注意的是,这个方法当索引值大于当前list的size或小于0时,会抛出IndexOutOfBoundsException异常,比如此时list.add(3,"bb");则会抛出异常(3>2)。
ArrayList的两种addAll方法,向list中存入集合,类似于add:
list.addAll(c);
list.addAll(index, c);
例程:
String[] str = {"ee","ff"};
list.addAll(Arrays.asList(str));
System.out.println(list.toString());//[bb, aa, cc, ee, ff]
String[] str2 = {"gg","hh"};
list.addAll(2, Arrays.asList(str2));
System.out.println(list.toString());//[bb, aa, gg, hh, cc, ee,ff]
ArrayList的set()方法,修改指定位置元素:
list.set(index, element);//在索引index的位置设置元素element,替换原先的元素
ArrayList的三种remove方法:
list.remove(int index);
list.remove(Object o);
list.removeAll(Collectionc);
List的indexOf()和lastIndexOf()方法,调用equals()方法去一个个比较,找到符合的就返回索引,一个从前检索,一个从后检索。
泛型集合中,不能添加泛型规定的类型及其子类以外的对象。泛型不能为基本类型,基本类型可以对应包装类泛型,泛型必须是引用类型。
Set无序不可重复,因此遍历set集合只能使用foreach或iterator,不能使用get()。set中,添加一个对象,无论添加多少次,仅保留一个该对象的引用,且只保留第一次添加的。
Map无序,key不可重复。
Map中的put()方法既可以添加也可以修改,因为若已有键值对,又put了一个相同键但不同值的键值对,则会替换原有的对应键值对。
keySet()方法得到Map中的所有键的一个Set类型的集合,通过键再获取所有对应的值。
keySet()获取Map中值的例程:
public static void getKeySet(Map map){
SetkeySet = map.keySet();
for (String key : keySet) {
System.out.println(key + ":" + map.get(key));
}
}
entrySet()方法获得Map中的所有键值对Set的集合,注意Entry也具有泛型,实际开发中要写清键值对应类型,通过该集合中存储的Entry的getKey()和getValue()方法获取对应的键值。
entrySet()获取Map中值的例程:
public static void getEntrySet(Map map){
Set entrySet = map.entrySet();
for (Entryentry : entrySet) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
Collection接口的contains() 和containsAll()方法,判断集合中是否包含指定元素对象或指定子集合,其底层实现为遍历集合,调用集合中对象的equals方法,一个个进行比较,因此,可以根据需要判断的内容相应地重写equals方法,List只调用其equals()方法,HashSet和HashMap基于哈希表实现,在调用equals()之前还要调用hashCode()。
例程(根据课程名判断):
public boolean equals(Object obj) {
if (this== obj)
return true;
if (obj== null)
return false;
if (!(objinstanceof Course))
return false;
Courseother = (Course) obj;
if (name== null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
returntrue;
}
HashSet的contains()和containsAll()方法,其实现是先通过hashCode()方法比较其返回的哈希码是否相同,若相同,再使用equals方法,只有在这两个方法都返回true的时候,contains()和containsAll()方法才会返回true,在实际开发中,根据需求重写hashCode()和equals()方法(可通过eclipse自动生成)。
HashMap中的containsKey()和containsValue()方法同HashSet,也要根据需求重写hashCode()和equals()方法(可通过eclipse自动生成)。
//随机生成指定长度的字符串并排序
public static void sortStringRandom(){
String base ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
List list = new ArrayList();
Random random = new Random();
for(int j = 0; j < 5; j++){
StringBuffer sb = new StringBuffer();
String str = "";
do{
for(int i = 0; i < 10; i++){
int num = random.nextInt(base.length());
sb.append(base.charAt(num));
}
str = sb.toString();
}while(list.contains(sb));
list.add(str);
}
System.out.println("-------------------排序前--------------------");
System.out.println(list.toString());
Collections.sort(list);
System.out.println("-------------------排序后--------------------");
System.out.println(list.toString());
}
Collections 的sort()方法,默认按照0-9(48--57)A-Z(65--90)a-z(97--122)
Collections集合类有两个sort()方法,对应有两种实现集合排序的方式,即
第一种:实现Comparable接口,重写List中存储对象的compareTo()方法。例程:
在Student类中重写compareTo(),
@Override
public int compareTo(Object o) {
return this.id.compareTo(((Student)o).id);
}
测试类中调用:Collections.sort(list);
注意:list中存储的是Student对象,实现通过学生的id从小到大排序,id为String类型,则一个字符一个字符地比较排序。
第二种:新建一个类,并实现Comparator接口,重写compare()方法,
public class BusComparator implements Comparator{
@Override
public int compare(Student o1, Student o2) {
Stringname1 = o1.getName();
String name2 = o2.getName();
Collator collatorChina =Collator.getInstance(java.util.Locale.CHINA);
return collatorChina.compare(name1, name2);
}
}
测试类中调用:Collections.sort(list, newBusComparator());
注意:
Collator collatorChina =Collator.getInstance(java.util.Locale.CHINA);
return collatorChina.compare(name1,name2);
这两行代码可以实现汉字按照拼音的比较排序。Collator对象的compare()方法,对于一次比较字符串效率很高,但对于字符串列表,使用getCollationKey().compareTo()方法具有最佳性能:
returncollatorChina.getCollationKey(name1).compareTo(collatorChina.getCollationKey(name2));
Collections.sort()方法默认按照参数的ASCII\unicode排序,int类型参数按照实际大小,String类型参数按照从前到后每个字符的ASCII码从小到大排序,例如,“10000”在“23”之前。
总结:java的集合框架中有五大组成——Collection接口(List、Queue和Set)、Map接口、Collections集合类、Comparable接口和Comparator接口。
按照指定字符串顺序比较大小,如JQKA,可以将其加入List集合中,使用indexOf()方法,比较其索引值。