赋值
A obj = new A();
obj 可以看作内存中一个对象的句柄
c/c++中,obj称为指针,java中称为Reference
对象赋值时Reference 赋值,而基本类型时直接拷贝值
基本类型的变量值小,可直接拷贝;对象包含多个值,不容易复制,赋值采用共享同一块内存区域。
函数中局部变量,编译器不会给默认值,需要初始化才可使用;
类的成员变量,编译器会给默认值,可以直接使用。
this 在类中的用法
1、指向本类中的成员变量
2、指向本类中的成员方法
3、可以当作构造函数使用
继承
子类继承父类所有的东西(但不能直接访问private成员)
Java所有类都继承自Java.lang.Object类
Java所有的类都是单根继承
子类构造函数默认第一句话都会去调用父类的构造函数
抽象类和接口相同点:两者都不能被实例化,不能new操作
抽象类和接口不同点
抽象类abstract,接口interface
抽象类可以有部分方法实现,接口所有方法不能有实现
一个类只能继承(extends)一个(抽象)类,实现(implements)多个接口
接口可以继承(extends)多个接口
抽象类有构造函数,接口没有构造函数
抽象类可以有main,也能运行,接口没有main函数
抽象类方法可以有private/protected,接口方法都是public
类转型cast
变量支持互相转化,比如inta=(int)3.5:
类型可以相互转型,但是只限制于有继承关系的类。
子类可以转换成父类,而父类不可以转为子类。
子类继承父类所有的财产,子类可以变成父类(从大变小,即向上转型);从父类直接变成子类(从小变大,即向下转型)则不允许。
Human obj1 = new Man();
//0K,Man extends Human
Man obj2 = new Human();
//illegal, Man is a derived class Human
父类转为子类有一种情况例外,就是这个父类本身就是从子类转化过来的。
Human objl = new Man(); //0K,Man extends Human
Man obj2 =(Man)obj1; //oK,because objl is born from Man class.
public class Man extends Human{
public void eat(){
System.out.println("I can eat more");
}
public void plough(){ }
public static void main(string[] a){
Man obj1 =new Man();
obj1.eat();// call Man.eat()
Human obj2=(Human)
obj2.eat();// call Man.eat()
Man obj3 =(Man)obj2;
obj3.eat();// call Man.eat()
}
}
多态
作用
以统一的接口来操作某一类中不同的对象的动态行为
对象之间的解耦
public interface Animal {
public void eat();
public void move();
}
public class cat implements Animal {
public void eat(){
System.out.println("Cat: I can eat");
}
public void move(){
System.out.println("cat:I can move");
}
}
public class dog implements Animal {
public void eat(){
System.out.println("Dog: I can eat");
}
public void move(){
System.out.println("Dog:I can move");
}
}
public class AnimalTest{
public static void main(
string[] args){Animal[] as = new Animal[4];
as[0]= new cat();
as[1]= new Dog();
as[2]= new Cat();
as[3]= new Dog();
for(int i=0;i<as.length;i++){
as[i].move(); //调用每个元素的自身的move方法
}
for(int i=0:i<as.length:i++){
haveLunch(as[i]);
}
haveLunch(new cat()); // Animal a =new Cat(); haveLunch(a);
haveLunch(new Dog());
haveLunch(
new Animal(){
public void eat(){
System.out.printIn("I can eat from an anonymous class");
}
public veid move(){
System.out,println("I can move from an anamymous class");
}
});
}
public static void haveLunch(Amimal a){
a.eat();
}
输出:
Dog:I can move
Cat:I can move
Dog:I can move
Cat:I can eat
Dog: I can eat
Cat:I can eat
Dog:I can eat
Cat:Ican eat
Dog:I can eat
I can eat from an anonymous class
契约设计
Java编程设计遵循契约精神
契约:规定规范了对象应该包含的行为方法接口定义了方法的名称、参数和返回值,规范了派生类的行为
基于接口,利用转型和多态,不影响真正方法的调用,成功地将调用类和被调用类解耦(decoupling)
类转型:子类可以转父类,父类不可以转子类(除非父类对象本身就是子类)
多态:子类转型为父类后,调用普通方法,依旧是子类方法
契约设计:类不会直接使用另外一个类,而是采用接口形式,外部可以“空投”这个接口下的任意子类对象。
static
静态变量,类共有成员
static变量只依赖于类存在(通过类即可访问),不依赖于对象实例存在。即可以通过Potato.price即可访问。
所有的对象实例,如例子中的obi1和obi2关于price变量的值都共享存储在一个共同的空间(栈)。
static方法
静态方法也无需通过对象来引用,而通过类名可以直接引用。
在静态方法中,只能使用静态变量,不能使用非静态变量。
静态方法禁止引用非静态方法。
查看例子StaticMethodTest.java。
关于static修饰类(内部类),使用的机会较少,暂忽略不计。
public class staticMethodTest{
int a = 111111;
static int b=222222;
public static void hello(){
System.out.println("000000");
System.out.println(b);
//System.out.printIn(a); //error, cannot call non-static variables
//hi()//error,cannot call non-static method
}
public void hi(){
System.out.println("333333");
hello(); //ok,call static methods
System.out.println(a);//ok,call non-static variables
System.out.println(b);//ok,call static variables
}
public static void main(string[] a){
StaticMethodTest.hello();
//staticMethodTest.hi();//error,不能使用类名来引用非静态方法
StaticMethodTest foo = new staticMethodTest();
foo.hello();// warning but it is ok
foo.hi(); //right
}
}
static块
-只在类第一次被加载时调用。
换句话说,在程序运行期间,这段代码只运行一次。
执行顺序:static块>匿名块>构造函数。
class staticBlock{
//staticl block>anonyous block >constructor function
static
{
System.out.println("2222222222222222222");
}
{
System.out.println("1111111111111111111111")
}
public staticBlock(){
System.out.println("33333333333333333333");
}
{
System.out.println("4444444444444444”)
}
}
比如当前类多次被初始化,22222222 只执行一次。
单例模式,
又名单态模式,Singleton。
限定某一个类在整个程序运行过程中,只能保留一个实例对象在内存空间。
内存空间中
ttern) 联只有
单例模式是GoF的23种设计模式(Design P)经典的一种,属于创建型模式类型。
单例模式:保证一个类有且只有一个对象
-采用static 来共享对象实例
-采用private 构造函数,防止外界new操作
public class Singleton{
private static singleton obj= new singleton(); //共享同一个对象
private string content;
private singleton()//确保只能在类内部调用构造函数
{
this.content ="abc";
}
public string getcontent(){
return content;
}
public void setContent(string content){t
his.content = content;
}
public static singleton getInstance()
//静态方法使用静态变量
//号外可以使用方法内的临时恋量,但是不能引用非静态的成员恋量
return obj;
}
public static void main(string[l args){
singleton obj1 =singleton.getInstance();
System.out.println(obj1.getcontent()); //abc
Singleton obj2=singleton.getInstance();
System.out.println(obj2.getcontent()); //abc
obj2.setcontent("def");
System.out.println(obj1.getcontent());//def
System.out.println(obj2.getcontent()); //def
System.out.println(obj1 == obj2);//true,obj1和obj2指向同一个对象
}
}
final
Java的final关键字同样可以用来修饰 _类 -方法 -字段
final的类,不能被继承,
父类中如果有final的方法,子类中不能改写此方法
final的变量,不能再次赋值。
如果是基本型别的变量,不能修改其值;
如果是对象实例,那么不能修改其指针(但是可以修改对象内部的值)
class FinalObject{
int a=10;
}
public class finalObjectTest{
public static void main(string[] args){// ToD0 Auto-generated method stubfinal F
inalobject obj1 = new Finalobject();
System.out.println(obj1.a); //10
obj1.a= 20;
System.out.println(obj1.a); //20
obj1 = new Finalobject(); //不可以
}
}
常量
public static final String a="hello";
接口中定义的变量 默认时常量。
常量池
Java为很多基本类型的包装类/字符串都建立常量池常量池:相同的值只存储一份,节省内存,共享访问
基本类型的包装类
-Boolean,Byte,Short,Integer, Long, Character, Float, DoubleBoolean:true,false
-Byte :-128~127,Character :0~127
Short,Int,Long: -128~127
Float,Double:没有缓存(常量池)
Java为常量字符串都建立常量池缓存机制
·字符串常量
public class stringconstantTest {
public static void main(string[] args){
String s1=“abc";
String s2 ="abc";
string s3 ="ab"+"c";//都是常量,编译器将优化,下同
String s4 ="a" + "b" +"c";
System.out.println(s1= s2);//true
System.out.println(s1 == s3);//true
System.out.println(s1 == s4);//true
}
}
基本类型的包装类和字符串有两种创建方式常量式
(字面量)赋值创建,放在栈内存(将被常量化)
Integer a=10;
String b=“abc”;
new对象进行创建,放在堆内存(不会常量化)
Integer c= new Integer(10);
String d=new String(“abc”);
这两种创建方式导致创建的对象存放的位置不同
public class BoxClassTest{
public static void main(string[] args){
int i1 = 10;
// 自动装箱工
Integer i2 = 10;
System.out.println(i1 ==i2);//true//自动拆箱 基本类型和包装类进行比较,包装类自动拆箱
Integer i3 = new Integer(10);
System.out.println(i1 == i3);//true//自动拆箱基本类型和包装类进行比较,包装类自动拆箱
System.out.println(i2 ==i3);//false
//两个对象比较,比较其地址。
//i2是常量,放在栈内存常量池中,i3是new出对象,放在堆内存中
Integer i4 = new Integer(5);
Integer i5 = new Integer(5);
System.out.println(i1 ==(i4+i5));//true
System.out.println(i2==(i4+i5));//true
system.out.println(i3 ==(i4+i5))://true
//i4+i5 操作将会使得i4,i5自动拆箱为基本类型并运算得到10.
//基础类型10和对象比较,将会使对象自动拆箱,做基本类型比较
Integer i6 =i4 + i5; // +操作使得i4,i5自动拆箱,得到10,因此i6 == i2.
System.out.println(i1 == i6);//true
System.out.println(i2 == i6);//true
System.out.println(i3 == i6);//false
}
}
基本类型和包装类比较,将对包装类自动拆箱
对象比较,比较地址
加法+会自动拆箱
常量赋值(堆内存)和new创建(栈内存)不是同一个对象
编译器只会优化确定的字符串,并缓存
public class stringNewTest{
public static void main(string[] args){
String s0 ="abcdef";
String s1 ="abc";
String s2 ="abc";
String s3 = new string("abc");
String s4 = new string("abc");
System.out.println(s1 ==s2);//true 常量池
System.out.println(s1== s3);//false 一个栈内存,一个堆内存
System.out.println(s3 == s4);//false 两个都是堆内存
System.out.println("=====================");
//涉及到变量,故编译器不优化
String s5 = s1 +"def";
String s6="abc"+"def";//都是常量 编译器会自动优化成abcdef
String s7 ="abc"+ new string("def");//涉及到new对象,编译器不优化
System.out.println(s5 ==s6);//false
System.out.println(s5 ==s7);//false
System.out.println(s6 ==s7);//false
System.out.println(s0 == s6);//true
System,out,println("=========================")
String s8=s3 +"def";//涉及到new对象,编译器不优化I
string s9=s4+"def";//涉及到new对象,编译器不优化
String s10=s3 + new string("def");//涉及到new对象,编译器不优化
System.out.println(s8==s9);//false
System.out.println(s8 ==s10);//false
System.out.println(s9 ==s10);//false
}
}
不可变对象和字符串
如何创建不可变对象
immutable对象是不可改变,有改变,请clone/new一个对象进行修改
所有的属性都是final和private的
不提供setter方法
类是final的,或者所有的方法都是final
类中包含mutable对象,那么返回拷贝需要深度clone
字符串的加法
String a= “abc
a=a+“def”;//由于String不可修改,效率差使用StringBuffer/StringBuilder类的append方法进行修改StringBuffer/StringBuilder 的对象都是可变对象
StringBuffer(同步,线程安全,修改快速),StringBuilder(不同步,线程不安全,修改更快)
classpath
Iava -classpath ,;c:\temp cn.com.test.ManC:temp
第一部分:java,执行命令,是java.exe的简写。
第二部分:-classpath 固定格式参数,可以简写成-cp.
第三部分:是一个(Windows分号,Linux/Mac冒号连接起来的)字符串。按分隔符隔开,得到一个个子路径。当运行cn.com.test.Man类的过程中,如果需要用到其他的类,就会分裂第三部分的字符串,得到多个子路径,然后依次在每个路径下,再去寻找相应类(全称,包名以点隔开对应到目录)第四部分:主执行类的全称(含包名)
编译和运行规则
-编译一个类,需要java文件的全路径,包括扩展名,
运行一个类,需写类名全称(非文件路径),无须写扩展名。
编译类的时候,需要给出这个类所依赖的类(包括依赖的类再次依赖的所有其他类)的所在路径,
运行类的时候,需要给出这个类,以及被依赖类的路径总和。
classpath参数也可以包含jar包。如果路径内有空格,请将classpath参数整体加双引号。
java -classpath.;c:\test.jar;c:\temp;c:\a bccn.com.test.Man
Java 访问权限
Java访问权限有四种 (方法、类)
private: 私有的,只能本类访问
default(通常忽略不写):同一个包内访问
protected:同一个包,子类均可以访问
public:公开的,所有类都可以访问
使用范围
四种都可以用来修饰成员变量、成员方法、构造函数
default和public可以修饰类
推荐 成员变量 都是private 成员方法都是public