一 基础部分
1.基本数据类型
Java的八种基本数据类型不支持面向对象的编程机制,不具备“对象”的特性:没有成员变量、方法可以调用。java之所以提供这八种基本数据类型,是为了照顾程序员的传统习惯。所有的引用类型的变量都继承了Object类,都可以当成Object类型变量使用,但是基本数据类型就不可以, 为了解决这个问题,Java提供了包装类。JDK1.5提供了自动装箱和自动拆箱功能,自动装箱是指,可以把一个基本数据类型的变量直接赋给对应的包装类变量或者是Object变量;自动拆箱是指允许直接把包装类对象直接赋给一个对应的基本类型变量。这里要注意,自动装箱和自动拆箱时必须要类型匹配,如 Integer只能自动拆箱成int,不能拆成boolean。
2.包装类
包装类还可以基本实现基本类型变量和字符串的转换,把字符串转换成基本类型有两种方式:
利用包装类提供的parseXxx(String s)静态方法;
利用包装类提供的Xxx(String s)构造器;
如:
String intStr="123"; int it1=Integer.parseInt(intStr); int it2=new Integer(intStr);
3.String类的转换
String类提供了多个重载value()方法,用于将基本类型变量转换成字符串:
int it3=111; String s=String.valueOf(it3); String booleanStr=String.valueOf(true);
还有一种更简单的方法,将基本类型和""进行连接运算:
String s=5+"";
4.包装类和基本数据类型的数据比较
包装类型的变量虽然是引用数据类型,但是包装类的实例可以与数值类型的值进行比较,这种比较是直接取出包装类实例所包装的数值来比较的,如:
Integer a=new Integer(6); System.out.println("6的包装类实例是否大于5.0"+(a>5.0));
两个包装类的实例比较
只有两个包装类引用指向同一个对象时才会返回true,如:
new Integer(2)==new Integer(2); //false
由于自动装箱功能,可能会出现一些特别的情况,如:
Integer a=2; Integer b=2; a==b; //true Integer c=128; integer d=128; c==d; //false
这里主要与java的Integer类的设计有关,系统自动把-128~127之间的整数自动装箱成Integer实例,并放入了一个Cache的数组中缓存起来,所以-128~127之间的同一个整数自动装箱成一个Integer实例时,实际上引用的是cache数组里的同一个数组元素,而在这范围之外的整数,系统总是重新创建一个Integer实例,所以引用的不是同一个对象。
5.toString()方法
如果在程序中定义了一个Person类
class Person{ private String name; public Person(String name){ this.name=name; } } public class PrintObject{ public static void main(String[] args){ Person p=new Person("lyy"); System.out.println(p); } }
打印出这个对象,结果为[email protected],实际上Person实例是一个内存中的对象,不可以直接转换成字符串输出。但是实际上,这里输出 的是Person对象的toString()方法的返回值,这里的p跟p.toString()效果是一样的。toString()方法是一个“自我描 述”方法,当程序员直接打印该对象时,系统会输出该对象的自我描述信息,用以告诉外界该对象具有的状态信息。toStrng()方法返回的是“类名[email protected]+hashCode”
6.==和equals方法
用==进行判断时,如果都是基本数据类型,且值相等,就返回true;如果是两个引用类型,只有指向同一个对象,==判断才会返回true,如:
int a=65; float b=65.0f; a==b; //true char c=‘A‘; a==c; //true String str1=new String("hello"); String str2=new String("hello"); str1==str2; //false str1.equals(str2); //true String str3="hello"; String str4="hello"; str3==str4; //true
这里的hello和new String("hello")的区别是:当程序直接使用形如"hello"的字符串直接量(也包括可以在编译时直接就能计算出来的字符串值)时,JVM 将会使用常量池来管理这些字符串,常量池保证相同的字符串直接量只有一个,不会产生多个副本;当使用String类的构造器来创建一个新的String对象,新创建的String对象被保存在堆内存中,该对象是运行时创建出来的。
可以将equals()方法重写,如:
public class Person{ private String name; private String idStr; public Person(String name,String idStr){ this.name=name; this.idStr=idStr; } public boolean equals(Object obj){ //如果两个对象是同一个对象 if(this==obj) return ture; //只有当obj是Person对象 if(obj!=null&obj.getClass()==Person.class){ Person p=(Person)obj; //并且当前对象的idStr与obj对象的idStr相等时才可以判断两个对象相等 if(this.getIdStr().equals(p.getIdStr())) { return true; } } return false; } }
7.static关键字
(1)static关键字修饰的成员就是类成员,static关键字不能修饰构造器,static修饰的类成员属于整个类,不属于单个实例。类变量生存范围几乎等同于该类的生存范围,当类完成初始化时,类变量也被初始化。类成员不能访问实例成员,因为类成员属于类,类成员的作用域比实例成员的作用域更大,完全可能出现类成员已经初始化完成,但实例成员还不曾初始化的情况。
(2)类变量也可以通过该类的对象来访问,但实际上并不是访问该对象所拥有的变量,因为系统在创建该类的对象时,并不会再一次为类变量分配内存,也就是说,对象根本不拥有对应类的类变量,只是系统会在底层转换为通过该类来访问类变量。
(3)单例类
有些时候,允许其他类自由创建该类的对象没有任何意义,还可能造成系统性能下降,因为频繁的创建对象、回收对象带来的系统开销的问题。比如系统只有一个窗口管理器,一个假脱机打印设备或一个数据库引擎访问点。
单例模式的几个特点:避免其他类自由创建该类的实例,构造器使用private,然后提供一个public方法作为该类的访问点来创建该类的对象,该方法只 能是static。另外,该类还必须缓存已经创建的对象,否则该类无法知道是否已经曾经创建过对象,也就无法保证只创建一个对象。因此该类需要使用一个成员变量来保存曾经创建的对象,因为该成员变量需要被上面的静态方法访问,故此成员变量必须使用static修饰。
单例模式是一种常见的设计模式,主要是两种:懒汉式和饿汉式
懒汉式
public class Singleton{ private static Singleton instance=null; private Singleton(){} public static Singleton getInstance(){ if(instance==null){ instance=new Singleton(); } return instance; } }
饿汉式
public class Singleton{ private static Singleton instance=new Singleton(); private Singleton(){} public static Singleton getInstance(){ return instance; } }
8.final
final关键字可用于修饰类、变量和方法,final修饰的变量不可被改变,一旦获得了初始值,该final变量的值就不能被重新赋值。
final可提高程序响应效率,声明成final的情况:
(1)不需要重新赋值的变量,包括类属性、局部变量;
(2)对象参数前加final,表示不允许修改引用的指向;
(3)类方法确定不允许被重写;
二 内部类
1.内部类的作用:
(1)内部类提供了更好的包装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类;
(2)内部类成员可以直接访问外部类的私有数据,但外部类不能访问内部类的实现细节,如内部类的成员变量;匿名内部类适用于创建那些仅需一次使用的类;
(3)内部类比外部类可以多使用三个修饰符:private protected static;
(4)非静态内部类不能拥有静态成员
2.内部类主要有非静态内部类和静态内部类
(1)非静态内部类:
public class Cow { private double weight; public Cow(double weight) { this.weight = weight; } public Cow() { } //非静态内部类 private class CowLeg{ private double length; private String color; public CowLeg(double length, String color) { this.length = length; this.color = color; } public CowLeg() { } public void info(){ System.out.println("牛腿颜色:"+color+",高:"+length); //可以访问到外部类的private修饰的成员变量 System.out.println("奶牛重:"+weight); } } public void test(){ CowLeg cl=new CowLeg(1.12,"白加黑"); cl.info(); } public static void main(String[] args){ Cow cow=new Cow(378.9); cow.test(); } }
注意:如果外部类成员变量、内部类成员变量和内部类方法里的局部变量同名,可以通过使用this,外部类类名.this来区分,如:
public class DiscernVariable { private String prop="外部类的实例变量"; private class innerClass{ private String prop="内部类的实例变量"; public void info(){ String prop="局部变量"; //外部类的实例变量 System.out.println(DiscernVariable.this.prop); //内部类的实例变量 System.out.println(this.prop); //局部变量 System.out.println(prop); } } public void test(){ innerClass in=new innerClass(); in.info(); } public static void main(String[] args){ new DiscernVariable().test(); } }
通过上面两个例子我们可以发现,如果存在一个非静态内部类对象,那么久一定存在一个被它寄生的外部类对象,如:
public class Outer { private int outProp=9; class Inner{ private int inProp=5; public void accessOutProp(){ System.out.println("外部类的outProp的值:"+outProp); } } public void accessInnerProp(){ //这段代码出现编译错误,外部类不能直接访问非静态内部类的实例变量 // System.out.println("内部类的inProp的值:"+inProp); //必须要显式创建内部类来访问内部类的实例变量 System.out.println("内部类的inProp的值:"+new Inner().inProp); } public static void main(String[] args){ //只是创建了外部类对象,并没有创建内部类对象 Outer out=new Outer(); out.accessInnerProp(); } }
(2)静态内部类
public class StaticInnerClassTest { private int prop1=5; private static int prop2=3; static class StaticInnerClass{ private static int age; public void accessOurProp(){ //无法访问外部类的实例变量 // System.out.println(prop1); System.out.println(prop2); } } }
3.在外部类以外使用内部类
(1)非静态内部类:
class Out{ class In{ public In(String msg){ System.out.println(msg); } } } public class CreateInnerInstance { public static void main(String[] args){ Out.In in=new Out().new In("测试信息"); } }
非静态内部类的构造器必须使用外部类对象来调用
(2)静态内部类:
class StaticOut{ static class In{ public StaticIn(String msg){ System.out.println("静态内部类的构造器"); } } } public class CreateStaticInnerInstance { public static void main(String[] args){ StaticOut.StaticIn in=new StaticOut().StaticIn(); } }