网站建设套餐电话,无锡公司网站制作,百度ai开放平台,网站开发与制作目录
一、Java程序初始化顺序
二、Java的Clone方法作用
三、 OverLoad#xff08;重载#xff09;与Override#xff08;重写#xff09;区别
四、abstract class#xff08;抽象类#xff09;与interface#xff08;接口#xff09;的异同
五、String、StringBuf…
目录
一、Java程序初始化顺序
二、Java的Clone方法作用
三、 OverLoad重载与Override重写区别
四、abstract class抽象类与interface接口的异同
五、String、StringBuffer、StringBuilder区别
六、“”、equals和hashCode的区别
七、字符串创建与存储的机制 一、Java程序初始化顺序
结论父类静态变量-父类静态代码块-子类静态变量-子类静态代码块-父类非静态变量-父类非静态代码块-父类构造方法-子类非静态变量-子类非静态代码块-子类构造方法
代码例题请写出下面程序的运行结果
package com.alphamilk.Example101;class Father{static String staticString a;static {System.out.println(staticString);System.out.println(b);}public String NonString c;{System.out.println(NonString);System.out.println(d);}
}
class Son extends Father{static String SonstaticString e;static {System.out.println(SonstaticString);System.out.println(f);}public String SonNonString g;{System.out.println(SonNonString);System.out.println(h);}
}
public class javaDemo {public static void main(String[] args) {Son son new Son();}
}二、Java的Clone方法作用 由于Java在处理基本数据类型如int、double、char等时候都是采用按值传递除此之外的数据类型都是按照引用传递方式执行。
这就会导致数据类型的备份出现问题基本数据类型可以通过值传递快速备份而对象引用会传递对象的地址这样会导致对备份的操作影响到原本的数据。如下案例
// 其它类型数据
class Person{public String name;public int age;Person(String name ,int age){this.name name;this.age age;}Overridepublic String toString() {return name:name age:age;}
}
public class JavaDemo {public static void main(String[] args) {
// 基本数据类型与备份int a 10;int b;b a;
// 对备份操作b 100;System.out.println(a);System.out.println(b);
// 其它类型与引用Person person new Person(小红,100);Person person1 person;
// 对备份进行操作person1.name 小黄;System.out.println(person);System.out.println(person1);}
} 可以看到由于对象类型的“”是引用传递传递的是对象的地址所以对备份的操作实际上就是对本体的操作. 所以想要使用备份就需要Object类中的Clone方法。而Object类是所有类的父类所以可以如下实现 1.实现Cloneable接口 2.覆写Clone方法 3.调用方法 //1.实现 Cloneable 接口
class Person implements Cloneable{public String name;public int age;Person(String name ,int age){this.name name;this.age age;}Overridepublic String toString() {return name:name age:age;}
// 2. 实现克隆方法public Person Clone(){Person per null;try {
// 强制转型per (Person)super.clone();}catch (CloneNotSupportedException e){e.printStackTrace();}return per;}
}
public class JavaDemo {public static void main(String[] args) {Person person new Person(小红,100);
// 3.调用Clone()方法Person person1 person.Clone();// 对备份对象进行操作person1.name 小黄;person1.age12;
// 输出对象System.out.println(person);System.out.println(person1);}
} 注意上述代码克隆是在对象中仅存在基本数据类型下这样的拷贝被称为浅拷贝。而一旦对象中还存在其它对象则需要用深拷贝实现拷贝内容. Clone分为浅拷贝和深拷贝 浅拷贝仅仅拷贝对象中只存在基本数据类型 深拷贝可以拷贝对象中包含的对象 深拷贝如下案例
class Student implements Cloneable{
// 基本数据类型int id;
// 其它引用对象类型Dateprivate Date birthDay new Date();public Date getBirthDay() {return birthDay;}
// 更改BirthDay方法public void ChangedBirthDay(){long intervalTime 3600*30;long time birthDay.getTime();birthDay.setTime(timeintervalTime);}// 覆写克隆方法public Student Clone(){Student student null;
// 浅层拷贝try {student (Student) super.clone();} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}
// 深层拷贝student.birthDay (Date) this.getBirthDay().clone();return student;}Overridepublic String toString() {
// 输出对象return Students id:id birthday is birthDay;}
}
public class JavaDemo2 {public static void main(String[] args) {Student student1 new Student();student1.id 10;Student student2 student1.Clone();student2.id 11;student2.ChangedBirthDay();System.out.println(student1);System.out.println(student2);} 深层拷贝相比与浅层拷贝需要额外对引用对象中其它对象进行拷贝。 三、 OverLoad重载与Override重写区别
overload 与 override 都是Java多态性的不同表现其中overload是类中多态性的显现
Overload重载 重载指的是同一个类中有多个方法名称相同但是参数不同的方法因此可以在编译时候就确定具体调用哪个方法。它是一种编译时候的多态重载可以看作一个类的多态。 Override重写 子类可以重写父类的方法因此同样的方法在父类和子类中有着不同的表现形式在Java语言中基类的引用变量不仅可以指向其实现类的实例对象也可以指向其子类的实例对象。同样接口的引用变量中可以指向其实现类的实例对象。 案例代码
class Person{String race;
// 父类方法public String printfInfo(String race){return 种族race;}
}
class Student extends Person{int id;String name;
// 实现构造方法重载(OverLoad)// 1.无参构造方法Student(){}
// 2.单参构造方法Student(String name){this.name name;}
// 3多参构造Student(String name ,int id){this.name name;this.id id;}
// 覆写方法/** 注意覆写时候参数也需要一致*/Overridepublic String printfInfo(String race) {return 种族race , 名称name idid;}
}
public class JavaDemo {public static void main(String[] args) {Student student new Student(Alpha,01);System.out.println(student.printfInfo(人类));}
} 区别 1.覆写是子类和父类之间的关系是垂直关系而重载是同一个类中方法之间的关系是水平关系。 2.覆写只能由一个方法或者一对方法产生关系方法的重载是多个方法之间的关系。 3.覆写要求参数列表相同而重载要求参数列表不同。 4.覆写关系中调用方法体是根据对象的类型对象对应存储空间类型来决定的而重载关系是根据调用时的实参列表和形参列表来选择方法体的。 四、abstract class抽象类与interface接口的异同
抽象类 如果一个类中包含抽象方法那么这个类就是抽象类。在Java中可以通过某些类或者是类中的方法声明为abstractabstract只能用来修饰类或者方法不能用来修饰属性来表示一个类是抽象类。只要包含一个抽象方法的类就必须声明为抽象类抽象类可以仅仅申明方法的存在而不去实现它被声明为抽象的方法不能包含方法体。在实现的时候必须包含相同的或者更低的访问级别(public - protectd -private ).抽象类在使用的过程中不能被实例化但是可以创建一个对象使其指向具体子类的一个示例抽象类的子类为父类中所有的抽象方法提供具体的实现。否则子类也将是抽象类。 接口 接口就是一个方法的集合在Java中接口是通过关键字interface来实现的在Java8之前接口中既可以定义方法也可以定义变量其中变量必须是public、static、final的。而且方法必须是public abstract 的。由于这些修饰符都是默认的。 在Java8之后可以通过关键字default给接口中的方法添加默认实现此外接口中还可以定义静态方法。 案例代码
interface category{
// 输出物种信息public void printInfo();
}
interface Breath{
// 生物进行呼吸public void Breath();
}
abstract class behavior{
// 定义抽象方法public abstract void shout();
// 定义普通方法public void jump(){System.out.println(进行跳跃);}
}
//只能继承一个抽象类
//但是能继承多个接口
class Person extends behavior implements Breath,category{// 覆写抽象类中的抽象方法Overridepublic void shout() {System.out.println(人类进行嚎叫);}// 实现接口category中的方法Overridepublic void printInfo() {System.out.println(种族人类);}
// 实现接口Breath方法Overridepublic void Breath() {System.out.println(呼吸类型有氧呼吸与无氧呼吸);}
}
public class JavaDemo {public static void main(String[] args) {Person person new Person();
// 执行覆写的方法person.printInfo();person.Breath();person.shout();}
}
不同点 抽象类 抽象类只能被继承通过extend并且一个类只能继承一个抽象类。抽象类强调所属关系其设计理念为is-a关系。抽象类更倾向于充当公共类的角色不适与日后重新对立面的代码进行修改。除了抽象方法以外抽象类中还可以包含具体数据和具体方法可以由方法的实现。抽象类不能被实例化其子类如果实现了继承中抽象类中的抽象方法后可以实例化子类否则子类也是抽象类不能被实例化。 接口 接口需要通过实现implements一个类可以实现多个接口。接口用于实现比较常用的功能以便于日后的维护和方法的增删。接口不是类而是一种对类的一组需求描述这些类需要遵循接口描述的统一格式进行定义。接口中所有的方法都是public的因此再实现接口的类中必须把方法声明为public因为默认类中访问属性是包可见的。而不涉及public这就相当于在子类中降低了方法的可见性会导致编辑错误。 五、String、StringBuffer、StringBuilder区别
在Java中可以操作字符串的有几大类包括String、StringBuffer、StringBuilder。 String是不可变类也就意味着一旦String对象一旦创建其值无法被改变而StringBuffer是可以改变的。所以当一个字符串需要经常修改的时候最好用StringBuffer来实现。因为不可变类其值在修改的时候其实原来的数据并没有被删除而是堆上创建了一个新的不可变类String的对象并且栈上对象指向了新的对象所以如果字符串大量修改的话就会产生大量的浪费资源的无用对象。最后被垃圾回收器回收。虽然这在小的项目里影响微乎其微但是在大项目中是会有非常大的效率问题。 StringBuilder也是可以被修改的字符串与StringBuffer相似都是字符串的缓冲区但是StringBuilder是线程不安全的。如果只是在单线程的情况下进行操作那么StringBuilder的效率是最快的。而多线程使用的时候StringBuffer使用是最好的。因为StringBuffer在有需要的时候可以进行方法的同步。 String与StringBuffer还有一点不同是在于初始化对象上String有两种初始化方式第一种是直接赋值第二种是通过构造函数赋值而StringBuffer只能通过构造函数创建对象。
使用的案例代码
public class JavaDemo {public static void main(String[] args) {
// 创建有序map查看效率排名MapLong,String map new TreeMap();// String的两种初始化对象方式String a String A;String b new String(String B);// StringBuffer唯一初始化对象方式StringBuffer buffer new StringBuffer(String C);
// StringBuilder初始化方式StringBuilder builder new StringBuilder(String D);// 单线程下分别测试效率
// String字符串long start System.currentTimeMillis();for (int i 0;i10000;i){a a Add String;}long end System.currentTimeMillis();long internal1 end - start;map.put(internal1,String类型运行时间);// StringBufferlong start2 System.currentTimeMillis();for (int i0;i10000;i){
// 调用StringBuffer内方法append即添加字符串buffer buffer.append(Add String);}long end2 System.currentTimeMillis();long internal2 end2 - start2;map.put(internal2,StringBuffer类型运行时间);// StringBuilderlong start3 System.currentTimeMillis();for (int i0;i10000;i){builder builder.append(Add String);}long end3 System.currentTimeMillis();long internal3 end3 - start3;map.put(internal3,StringBuilder类型运行时间);System.out.println(map);}
} 可以多次运行代码或者提高循环次数查看平均值 单线程保证线程安全下 效率速度 StringBuilderStringBufferString 六、“”、equals和hashCode的区别 “”运算符在基本数据类型中是用于判断两个变量的值是否相同但是如果两个变量是引用数据类型那么“”就是两个变量对应的引用地址的比较。 equals是Object类中提供的方法由于所有类都继承了Object主类所以所有对象都是可以调用equals方法。相比于“”运算符equals方法的特殊之处就是在于它是可以被覆盖的也就意味着它并不是比较引用的地址而是比较对象中的属性。 hashCode方法是从Object类中继承过来的他也是用来鉴定两个对象是否相等。Object类中的hashCode()方法返回对象在内存中的地址并转换成一个int值所以如果没有重写hashCode()方法任何对象的hashCode方法都是不相等的。也即是哈希值唯一的。
请你写出下面程序的执行结果
class Person{String name;Person(String name){this.name name;}
}
public class JavaDemo {public static void main(String[] args) {String a new String(content);String b new String(content);String c content;String d content;System.out.println(1: (ab));System.out.println(2:a.equals(b));System.out.println(3:(c b));System.out.println(4: (c a));System.out.println(5: (d c));int base1 1 ,base2 1;Integer integer 1;Integer integer1 1;System.out.println(6: (base1base2));System.out.println(7: integer1.equals(integer));Person person new Person(张三);Person person1 new Person(张三);System.out.println(8:(integer.hashCode() integer1.hashCode()));System.out.println(9:(c.hashCode() a.hashCode()));System.out.println(10:(person.hashCode() person1.hashCode()));}
} 注意 9true 解释 --String 类是一个特殊的类它有一个特殊的属性即字符串常量池String Pool。当我们使用字面量创建字符串时例如 String c contentJava会首先检查字符串常量池中是否已经存在相同内容的字符串如果存在则直接返回该字符串的引用如果不存在则在常量池中创建一个新的字符串对象并返回其引用。 因此在这段代码中虽然 a 和 b 是通过 new 关键字创建的两个不同的字符串对象但它们的内容相同。而 c 和 d 则是通过字面量创建的字符串它们的内容也相同。由于字符串常量池的存在c 和 d 实际上是指向同一个字符串对象的引用因此它们的地址是相同的。 10true解释 --对于 Integer 类型的对象Java在内部维护了一个缓存池用于缓存-128 ~ 127之间的整数对象。当我们通过 Integer.valueOf() 方法创建一个整数对象时如果该整数在缓存池中已经存在则直接返回该整数对象的引用否则在堆内存中创建一个新的整数对象并将其加入到缓存池中然后返回其引用。 七、字符串创建与存储的机制
在Java语言中对String对象提供给了专门的存储机制。
public class StringPool {public static void main(String[] args) {// 第一种存储
// 将abc放到常量区abc在编译时候产生String s abc;
// 将ab与c转为字符串常量“abc”并存在常量区String s1 abc;// 第二种存储
// 在堆中创建新的对象堆中对象指向常量区String s2 new String(abc);String s3 new String(abc);// 分别输出四个常量地址System.out.println(s地址s.hashCode());System.out.println(s1地址s1.hashCode());System.out.println(s2地址s2.hashCode());System.out.println(s3地址s3.hashCode());}
}第一种存储String s abc 在当创建一个字符常量的时候会首先在字符串常量池中进行查找是否已经有相同的字符串常量。具体原理就是通过调用方法equals方法进行一 一匹配 如果不存在则需要先进行创建一个对象然后将其加入字符串池中再将它引用返回。而如果存在的话直接获取对其的引用。而能够设置一个常量池的原因在于String类是一个不可变类无法对其进行修改日常对其进行修改本质是创建了一个新的字符串。 第二种存储String s1 new String(abc); 有区别第一种第二种存储需要对其操作进行拆分其多了一个new操作这个操作是在堆上创建一个对象并将值存放在堆中。是独立进行存储的与常量池无关。 从分析中可以看出在创建字符串对象时候会根据不同的情况来确定字符串是存储在堆中还是常量池中。而intern方法就是用于将字符串存入常量池中。 所以通过intern方法可以将new关键字创建堆内的字符串对象存入字符串常量池中。
但是要注意的是intern方法随着JDK的更新方法也随着更新。以下是其JDK1.6以下和JDK1.7以后的一些区别。 在 JDK 1.6 及之前的版本中调用 intern() 方法会将字符串复制一份到字符串常量池并返回字符串常量池中的引用。如果字符串常量池中已经存在相同值的字符串intern() 方法会返回常量池中的引用否则会在常量池中创建一个新的实例并返回该引用。而在 JDK 1.7 及之后的版本中调用 intern() 方法会检查字符串常量池中是否存在相同值的字符串。如果存在则返回常量池中的引用如果不存在则将字符串的引用直接存储到字符串常量池中并返回该引用。换句话说对于 JDK 1.7 及之后的版本如果原始字符串已经在常量池中存在调用 intern() 方法不会创建新的实例而是直接返回常量池中的引用。