【java】java面试高频知识点2

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);
    }
}
posted @ 2023-02-15 14:09  吴承勇  阅读(22)  评论(0编辑  收藏  举报