1.重写重载
重写:继承时对父类的方法重写该方法内容,方法类型是不变的,即返回类型,方法名字,参数都不变。值得注意的是可以改变权限,只能提高不能降低
重载:是一个类中有多个名字相同的方法,不考虑返回类型和参数名字,只考虑参数个数和参数类型。
访问权限:
依次排下来是 public、protected、友好的、privated. 不能用protected和privated修饰类。
protected和友好的差别如下:当父类和子类不在同一个包中,子类除了会继承public修饰的函数和变量之外,还会继承protected的,但是友好的就不会了
注:友好的就是啥都不写,默认友好权限。
子类继承父类时,如果父类有无参数的构造函数会自动调用,如果没有需要在子类构造函数的第一条写super();调用其带参数的构造函数。 因为子类是不继承构造函数的。
接口中的方法一定是public abstract的,实现接口的非抽象类必须明确的写出public,因为不能降低访问权限。
接口和abstract的区别是 接口只能有常量,不能有变量;接口的所有方法都是abstract的。
内部类:内部类就是在类里面的类,其不可以申明类方法和类变量,仅供其内嵌类使用。是唯一可以被static修饰的类
2.java 序列化和反序列化
2.1 概念:
将Java对象转换成字节流用来保存或者是移动,反序列化就是将字节流转换成Java对象
2.2 实现方式:
Java对象的序列化有两种方式。
- 是相应的对象实现了序列化接口Serializable
这个使用的比较多,对于序列化接口Serializable接口是一个空的接口,它的主要作用就是
标识这个对象时可序列化的,jre对象在传输对象的时候会进行相关的封装。这里就不做过多的介绍了。
直接看自己写的代码:
点击查看代码
import java.io.*;
public class TestSerializable implements Serializable {
private String Name;
private transient String sex;//加上transient就标志不会序列化了
private static String height; //静态变量也不会被序列化
public TestSerializable(String name, String sex) {
Name = name;
this.sex = sex;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public static String getHeight() {
return height;
}
public static void setHeight(String height) {
TestSerializable.height = height;
}
@Override
public String toString() {
return "TestSerializable{" +
"Name='" + Name + '\'' +
", sex='" + sex + '\'' +
", height='" + height + '\'' +
'}';
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
FileOutputStream fos = new FileOutputStream("Object.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
TestSerializable test = new TestSerializable("张三", "男");
oos.writeObject(test);
oos.close();
FileInputStream fis = new FileInputStream("Object.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
TestSerializable readObject = (TestSerializable)ois.readObject();
System.out.println(readObject);
ois.close();
}
}
- 实现序列化的第二种方式为实现接口Externalizable,Externlizable接口是继承了Serializable接口的
首先,我们在序列化对象的时候,由于这个类实现了Externalizable 接口,在writeExternal()方法里定义了哪些属性可以序列化,
点击查看代码
/** * 序列化操作的扩展类 */
@Override
public void writeExternal(ObjectOutput out) throws IOException {
//增加一个新的对象
Date date=new Date();
out.writeObject(userName);
out.writeObject(password);
out.writeObject(date);
}
/** * 反序列化的扩展类 */
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
//注意这里的接受顺序是有限制的哦,否则的话会出错的
// 例如上面先write的是A对象的话,那么下面先接受的也一定是A对象...
userName=(String) in.readObject();
password=(String) in.readObject();
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
Date date=(Date)in.readObject();
System.out.println("反序列化后的日期为:"+sdf.format(date));
}
重写了这两个方法之后,就可以使用正常的ObjectOutputStream, ObjectInputStream 将Java对象保存到文件中或者是从文件中读取到Java对象。
对于实现Java的序列化接口需要注意一下几点:
1.Java中的序列化时transient变量(告知Java该变量不可以被序列化,用于一些敏感安全考量的变量)和静态变量不会被序列
2.也是最应该注意的,如果你先序列化对象A后序列化B,那么在反序列化的时候一定记着Java规定先读到的对象 是先被序列化的对象,不要先接收对象B,那样会报错.尤其在使用上面的Externalizable的时候一定要注意读取 的先后顺序。
3.实现序列化接口的对象并不强制声明唯一的serialVersionUID,是否声明serialVersionUID对于对象序列化的向 上向下的兼容性有很大的影响。
3、泛型和不定参数
3.1 泛型应用
主要有三个:泛型类,泛型接口,泛型方法
泛型类:
//此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
//在实例化泛型类时,必须指定T的具体类型
public class Generic<T>{
//key这个成员变量的类型为T,T的类型由外部指定
private T key;
public Generic(T key) { //泛型构造方法形参key的类型也为T,T的类型由外部指定
this.key = key;
}
public T getKey(){ //泛型方法getKey的返回值类型为T,T的类型由外部指定
return key;
}
}
泛型的类型参数只能是类类型(包括自定义类),不能是简单类型
传入的实参类型需与泛型的类型参数类型相同
泛型接口:
//定义一个泛型接口
public interface Generator<T> {
public T next();
}
/**
* 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
* 即:class FruitGenerator<T> implements Generator<T>{
* 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"
*/
class FruitGenerator<T> implements Generator<T>{
@Override
public T next() {
return null;
}
}
/**
* 传入泛型实参时:
* 定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator<T>
* 但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。
* 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
* 即:Generator<T>,public T next();中的的T都要替换成传入的String类型。
*/
public class FruitGenerator implements Generator<String> {
private String[] fruits = new String[]{"Apple", "Banana", "Pear"};
@Override
public String next() {
Random rand = new Random();
return fruits[rand.nextInt(3)];
}
}
泛型方法:
泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型 。
/**
* 泛型方法的基本介绍
* @param tClass 传入的泛型实参
* @return T 返回值为T类型
* 说明:
* 1)public 与 返回值中间<T>非常重要,可以理解为声明此方法为泛型方法。
* 2)只有声明了<T>的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
* 3)<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
* 4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
*/
public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
IllegalAccessException{
T instance = tClass.newInstance();
return instance;
}
不定参数:不定参数其实就是个传入个数组,值得注意的是:
不定参数必须是最后一个参数
只能有一个不定参数
package Indefinite_parameter;
/**
* 测试Java不定参数
*/
public class Test {
public void display(int[] arr, int...arg) { //java 不定参数其实就是个传入个数组
for (int i = arg[0]; i <= arg[1]; i++) {
System.out.print(arr[i] + " ");
}
}
public static void main(String[] args) {
Test test = new Test();
int[] arr = {1,2,3,4,5};
test.display(arr,2,3);
}
}
4、反射
4.1、什么是反射?
就是对于任何一个类都能通过反射知道其的方法和属性,对于任意一个对象都能够调用它的任意一个方法或属性。这个动态的过程就叫反射。
4.2、那反射的机理上怎样的呢?
类加载的时候,通过类加载器将.Class文件载入到JVM当中,将Class文件读取入内存,同时产生class对象,一个类只产生一个Class对象。
4.3、反射的使用
首先怎么获得反射类对象,一共有四种方法:
- 类对象.getClass();
任何数据类型(包括基本数据类型)都有一个“静态”的class属性 - 通过Class类的静态方法:forName(String className)(常用)
package TestReflect;
import java.lang.reflect.Field;
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
TestReflect testReflect = new TestReflect("吴承勇", 1, 1000.0);
System.out.println();
Class testReflectClass1 = testReflect.getClass();
Class testReflectClass2 = TestReflect.class;
Class testReflectClass3 = Class.forName("TestReflect.TestReflect");//包名加类名,不知道是什么可以用testReflectClass1.getName()看看
}
}
- 通过类名.class对象
Class c3 = User.class
- 基本类型的包装类都有一个Type属性
Class c4 = Integer.Type;
Class类提供了四个public方法,用于获取某个类的构造方法:
Constructor getConstructor(Class[] params)根据构造函数的参数,返回一个具体的具有public属性的构造函数
Constructor getConstructors() 返回所有具有public属性的构造函数数组
Constructor getDeclaredConstructor(Class[] params) 根据构造函数的参数,返回一个具体的构造函数(不分public和非public属性)
Constructor getDeclaredConstructors() 返回该类中所有的构造函数数组(不分public和非public属性)
#constructor.newInstance()
与获取构造方法的方式相同,存在四种获取成员方法的方式。
Method getMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的具有public属性的方法
Method[] getMethods() 返回所有具有public属性的方法数组
Method getDeclaredMethod(String name, Class[] params) 根据方法名和参数,返回一个具体的方法(不分public和非public属性)
Method[] getDeclaredMethods() 返回该类中的所有的方法数组(不分public和非public属性)
#method.invoke()
存在四种获取成员属性的方法
Field getField(String name) 根据变量名,返回一个具体的具有public属性的成员变量
Field[] getFields() 返回具有public属性的成员变量的数组
field.setAccessible(true); #关闭安全检测,就可以对私有变量操作了
Field getDeclaredField(String name) 根据变量名,返回一个成员变量(不分public和非public属性)
Field[] getDelcaredFields() 返回所有成员变量组成的数组(不分public和非public属性)
4.4、反射的使用场景
场景1:
Tomcat具体加载处理细节
(1) Tomcat(App)首先读取配置文件web.xml中配置好的Servlet的子类名称
(2) Tomcat根据读取到的客户端实现的Servlet子类的类名字符串去寻找对应的字节码文件。如果找到就将其加载到内存。
(3) Tomcat通过预先设置好的Java反射处理机制解析字节码文件并创建相应的实例对象。之后调用所需要的方法。
简单的来说就是通过反射让用户填写配置文件,而不是面对源代码
场景2:
Spring框架AOP的底层,通过反射的原理,做到了一个动态代理类代理一个接口,只要是实现这个接口的类都可以代理
4.5、如何提高性能
目前知道的有两种方法:
第一种, 通过SetAccessible()方法,这个方法的源码解释如下,设置为true的时候会忽略Java语言的检查,性能可以提升很多
SomeObject someObject = new SomeObject();
Class<? extends SomeObject> cls = SomeObject.class;
Method method = cls.getDeclaredMethod("someGetMethod");
method.setAccessible(Boolean.TRUE);
String xxx = (String) method.invoke(someObject);
第二种,将获取的方法和属性保存下来,这样就不用每次都掉用了。
标签:知识点,序列化,java,String,接口,泛型,高频,方法,public From: https://www.cnblogs.com/wcyblogs/p/17122624.html