参考链接: Java中的final最终变量
java对象的序列化
Java序列化是指把Java对象转换为字节序列的过程;而Java反序列化是指把字节序列恢复为Java对象的过程。java中存有Cloneable接口,实现此接口的类都具有被拷贝能力,比new一个对象要快,拷贝分为浅拷贝和深拷贝,浅拷贝导致对象属性不彻底。
class Professor
{
String name;
int age;
Professor(String name,int age)
{
this.name=name;
this.age=age;
}
}
class student implements Cloneable
{
String name;
int age;
Professor p;
student(String name,int age,Professor p)
{
this.name=name;
this.age=age;
this.p=p;
}
public Object clone()
{
student o=null;
try
{
o=(student)super.clone();
}
catch(CloneNotSupportedException e)
{
System.out.println(e.toString());
}
return o;
}
public static void main(String[] args)
{
Professor p=new Professor("wang",5);
student s1=new student("zhangsan",1,p);
student s2=(student)s1.clone();
s2.p.name="lisi";
s2.p.age=3;
System.out.println("name="+s1.p.name+","+"age="+s1.p.age);
}
}
如代码中s2变了,s1也变了,说明他们指向同一个对象,这就是浅复制,关键是在clone()方法上,他并不是将对象的所有属性全拷贝过来,而是选择性拷贝,拷贝规则为:1)基本类型,只拷贝其值。2)实例对象,拷贝其地址引用,新拷贝对象原对象共用该实例。3)字符串,拷贝地址引用,修改时会从字符串常量池中新生一个原字符串不变。解决办法在clone里新建一个对象。但是在如果大量对象都是拷贝生成,每个类都写一个clone()方法,工程量就很大。
序列化实现对象的复制。通过字节流拷贝对象
public class CloneUtils {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj){
T cloneObj = null;
try {
//写入字节流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(obj);
obs.close();
//分配内存,写入原始对象,生成新对象
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
//返回生成的新对象
cloneObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
}
使用该工具类的对象必须要实现Serializable接口,否则是没有办法实现克隆。无须继承cloneable接口实现clone()方法。
Static关键字
Static代表全局和静态的意思,可以修饰成员变量和成员方法,也可修饰代码块。java的内存分配有栈和堆,栈中存放基本变量,数组和对象引用,堆中存放对象,当有static修饰的变量或方法,则会为其分配固定区域切既然是静态那他作用于内是不变的,删除了就不会再有。static修饰的变量是为类所共有,不依赖于实例,先于对象而存在,任一实例修改其他实例也会使用修改后的变量值。java编程思想中有一句话"static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”这段话虽然只是说明了static方法的特殊之处,但是可以看出static关键字的基本作用,简而言之,一句话来描述就是:方便在没有创建对象的情况下来进行调用(方法/变量)。
static修饰的变量:静态变量,在类加载时候完成初始化,在内存中仅有一个,jvm也只会为他分配一次内存,所有实例共享,可通过类名直接访问。实例变量与实例共存亡。在对象之间共享数据或方便访问时用静态变量。非静态变量是对象所拥有创建对象时初始化存在多个副本,各个对象的副本相互不影响。静态变量的初始化顺序是按照定义的数序进行初始化。
静态方法:可以通过类名直接访问Math类的所有方法都是static的,不依赖于对象 可以进行访问,没有对象那么静态方法是没有this的。静态方法中不可以访问非静态成员方法或变量,但是非静态成员方法可以访问静态/变量。(静态依赖于类普通依赖于对象的创建)。
代码块:静态代码块会随着类的加载一块执行,而且他可以随意放,可以存在于该了的任何地方。可以有多个,在类初次被加载时会按照static块的顺序来执行每个块并且只执行一次。
java中的static和c++中的是不一样的,java中static不会影响到变量或者方法的作用域,能够影响作用域的只有private、public、protected
public class Test {
public static void main(String[] args) {
System.out.println(s.age);//报错The field s.age is not visible
System.out.println(s.name);
}
}
class s{
public static String name="zhangsan";
private static int age=10;
}
private修饰的原因造成。在静态方法中没有this,在非静态中通过this访问非静态成员变量会怎样。
public class Test {
static int value = 10;
public static void main(String[] args) {
new Test().show();
}
private void show() {
int value = 1;
System.out.println(this.value);
}
}
结果为10.this代表当前对象,new Test()调用show的对象就是new Test()生成的对象。static变量是所有对象共享,show是局部变量不可能与this关联,所以输出10,静态对象独立于对象但是仍可以通过对象访问。java语法规定static不允许修饰局部变量。Static也存在一些缺陷。1)它只能调用static变量。2)它只能调用static方法。3)不能以任何形式引用this、super。
4)static变量在定义时必须要进行初始化,且初始化时间要早于非静态变量。无论是变量,方法,还是代码块,只要用static修饰,就是在类被加载时就已经准备好了,也就是可以被使用或者已经被执行,都可以脱离对象而执行。反之,如果没有static,则必须要依赖于对象实例。
public class Test {
Person person = new Person("Test");
static{
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
public static void main(String[] args) {
new My();
}
}
class Person{
static{
System.out.println("person static");
}
public Person(String str) {
System.out.println("person "+str);
}
}
class My extends Test {
Person person = new Person("My");
static{
System.out.println("myc static");
}
public My() {
System.out.println("my constructor");
}
}
test static 1、首先加载Test类执行静态代码块,然后执行My()my static 2、因没加载且其继承Test先加载Test,但已加执行my其静态方法person static 3、加载后执行构造函数,生成对象先初始化父类的成员变量,执行new person()但是没有加载person类,先加载就会执行person的静态方法person Test 4、完成成员初始化。test constructor 5、完成父类构造器完成初始化person My 6、自身成员变量初始化my constructor 7/构造函数初始化
final关键字
final最终的意思,他修饰的部分不会改变,final修饰数据可以看做常量,编译期常量,永远不改变,运行期初始化希望他也不变。编译期的常量在编译时即可参与运算在类加载完成后不可改变,编译期常量只能用基本类型,在定义时要初始化。运行期常量可以是基本类型和引用类型,基本类型其值不变,引用类型引用不变,应用对象的内容可以变
final修饰方法:最终的方法,不可被继承更改,使用final修饰方法,是为了锁定方法,父类的final方法是不能被子类所覆盖的,也就是说子类是不能够存在和父类一模一样的方法的。
final修饰类,不能被继承,final修饰的类成员变量可以是final也可以不是,成员方法默认final。
如果final修饰参数,代表该参数不可改变。
final和static在一起使用时即可修饰成员变量,也可修饰成员方法。对于成员变量,该变量一旦赋值就不能改变,我们称它为“全局常量”。可以通过类名直接访问。对于成员方法,则是不可继承和改变。可以通过类名直接访问。