Java基础常识(适用于面试)

本文深入讲解Java中的关键概念,包括八大数据类型、final与static特性、多态与抽象类、线程管理、序列化机制及类加载过程。同时探讨了异常处理、内存管理及面向对象编程原则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 八大数据类型的对应类里有常量表示类型的最大值最小值等取值范围
  2. 局部变量不能被声明为 static 变量
  3. final 对象的引用不能改变,但是里面的值可以改变
  4. 类中的 final 方法可以被子类继承,但是不能被子类修改
  5. final 类不能被继承
  6. 如果一个类包含抽象方法,那么该类一定要声明为抽象类
  7. volatile:使两个不同的线程总是看到某个成员变量的同一个值
  8. 接口可多重继承接口(extends)
  9. 普通的类方法是可以和类名同名的,和构造方法唯一的区分就是,构造方法没有返回值。
  10. 对象数组默认是填充null,基本类型是有值的
  11. 启动一个线程使用的是start而不是run方法
  12. 守护线程最典型的应用就是 GC (垃圾回收器)
  13. 全局变量主动初始化,基本类型为0,引用类型为null。局部变量需要手动初始化,否则不能通过编译
  14. Java中没有引用传递只有值传递,传递的是值的拷贝,也就是说传递后就互不相关了
    1. “在Java里面参数传递都是按值传递”这句话的意思是:按值传递是传递的值的拷贝,按引用传递其实传递的是引用的地址值,所以统称按值传递。
    2. 在Java里面只有基本类型和按照下面这种定义方式的String是按值传递,其它的都是按引用传递。就是直接使用双引号定义字符串方式:String str = “Java私塾”;
  15. transient关键字只能修饰变量(本地变量是不能被transient关键字修饰的),被修饰的变量将不再是对象持久化的一部分,一个静态变量不管是否被transient修饰,均不能被序列化。为什么要禁止某些变量序列化,譬如一些敏感信息在网络上传输。Externalizable接口也可以序列化对象,但是要重写其序列化方法,且跟transient无关
  16. 继承是子类使用父类的方法,而多态则是父类使用子类的方法。
  17. override是重写(覆盖)了一个方法,以实现不同的功能。重写(覆盖)的规则:
    1. 重写方法的参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载.
    2. 重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private)
    3. 重写的方法的返回值必须和被重写的方法的返回一致
    4. 重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类
    5. 被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写
    6. 静态方法不能被重写为非静态的方法(会编译出错)
  18. overload是重载,一般是用于在一个类内实现若干重载的方法,这些方法的名称相同而参数形式不同
  19. 对象比较使用equals方法
  20. 普通方法可以和类同名,但必须显示指定返回值(void也可以)。不过最好不要这么做。
  21. 对象数组未初始化默认是null,基本类型譬如int默认是0
  22. 线程分为守护线程和非守护线程(又叫用户线程)。GC为守护线程
  23. volatile关键字用在多线程同步中,他不能保证线程安全,JVM只是保证从主内存中加载到线程工作内存中的值是最新的读取值。
  24. 接口描述系统对外提供的所有服务,所以其成员必须是public的;接口的方法必须是抽象的;接口不能被实例化,所以没有构造方法,没有实例变量,只有静态变量且未final的不可变(常量)。接口是为了提供统一的抽象,既然统一,就要求里面的东西只能被实现而不能改。
  25. Java创建对象的四种方法:
    1. 使用new关键字
    2. 使用反射,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。
    3. 调用对象的clone()方法。
    4. 运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法
  26. 默认ArrayList的长度是10个,如果在new的时候加上参数例如ArrayList list = new ArrayList(20),那么会一次性分配20。如果未指定,则从10个扩充1.5倍到15个。。
  27. public class NULL {
        public static void haha(){
         	System.out.println("haha");
        }
        public static void main(String[] args) {
            ((NULL)null).haha();
        } 
    }
这个代码是合法的,但null强制转换后是无效对象,其返回值还是为null。但这里调用的是类的静态方法,所以是有效的
  1. 静态块和变量是在JVM加载类的时候执行的。静态变量和静态初始化块是依照他们在类中的定义顺序进行初始化的。同样,变量和初始化块也遵循这个规律。类实例化的初始化顺序依次是(静态变量、静态初始化块)>(变量、初始化块)>构造器。如果有继承那么是:(父类静态变量、父类静态块)>(子类静态变量、子类静态块)>(父类变量、父类初始化块)>(父类构造方法)>(子类变量、子类初始化块)>(子类构造方法)。其中括号内的优先级相同,在代码前面的先执行。
  2. 一般将父类异常类即Exception老大放在catch语句块的最后一个,因为子类异常也会匹配父类异常。catch中子类在前,父类在后
  3. RandomAccessFile是IO包的类,但是其自成一派,从Object直接继承而来。
  4. switch case中,记得加break
  5. 抽象类遵循的原则:
    1. abstract只能修饰类和方法,不能修饰字段
    2. 抽象类不能被实例化,只能被继承
    3. 抽象方法不能做实现
    4. 含有抽象方法的类必须定义为抽象类
    5. 抽象类里的方法被继承后可以选择性的实现,而接口则必须全部实现
    6. 抽象类是is-a的关系,借口是has-a的关系
    7. 接口默认成员变量是public static的,而抽象类是friendly的(其实类中只要不指定访问修饰符,都是friendly的)
  6. 子类被实例化时,会默认调用父类的无参构造参数(无论子类是否带参数)。如果没有构造函数,编译器会给你加个无参构造函数。如果你自己写了带参数的构造函数,那么编译器不会给你添加无参构造函数。此时如果你不显示的调用父类构造函数(super),那么编译出错
  7. 多态的运用,见如下代码(当调用了父类构造函数的时候,子类的初始化还没有开始,所以其成员变量还是null值)
public class Dervied extends Base {

    private String name = "dervied";

    public Dervied() {
        tellName();
        printName();
    }
    
    public void tellName() {
        System.out.println("Dervied tell name: " + name);
    }
    
    public void printName() {
        System.out.println("Dervied print name: " + name);
    }

    public static void main(String[] args){
        
        new Dervied();    
    }
}

class Base {
    
    private String name = "base";

    public Base() {
        tellName();
        printName();
    }
    
    public void tellName() {
        System.out.println("Base tell name: " + name);
    }
    
    public void printName() {
        System.out.println("Base print name: " + name);
    }
}
  1. Vector和ArrayList的区别:
    1. ArrayList在内存不够时默认是扩展50% + 1个,Vector是默认扩展1倍。
    2. Vector提供indexOf(obj, start)接口,ArrayList没有。
    3. Vector属于线程安全级别的,但是大多数情况下不使用Vector,因为线程安全需要更大的系统开销。
  2. System.gc()是建议调用gc 不保证调用时间 作用还是有的
  3. import static ,这个是静态导入,可以直接把某个类的静态方法导进来用,如:import static org.junit.Assert.*;这样,我们就可以直接在类中使用assertEquals方法了
  4. 在java的浮点型运算中:正浮点/0,结果为Infinity, 表示无穷大;负浮点/0,结果为-Infinity,表示无穷小。如果是整型/0 那会抛出异常。这就是为什么浮点运算可以除以0.
  5. Externalizable接口继承了Serializable接口,扩展了writeExternal和readExternal方法,这两个方法分别传入了一个ObjectOutput和ObjectInput,用于实现具体的序列化,所以该接口可以确定哪些属性被序列化,哪些又不需要序列化。值得注意的是,output和input的属性顺序必须一致。
  6. RMI默认端口为1099。RMI依赖于Java远程消息交换协议JRMP(Java Remote Messaging Protocol),该协议为java定制,要求服务端与客户端都为java编写。由于方法参数与返回值最终都将在网络上传输,故必须是可序列化的。
  7. Object.hashcode()方法是个native方法,具体实现被隐藏。根据网友使用c++测试,返回的不一定是内存地址,取决于具体运行环境(android windows 以及Oracle jdk open jdk)
  8. doublefloat不会出现数据误差,而floatdouble有误差:127.1f转double为127.0999984741211。如果需要无误差的转,使用BigDecimal。
  9. List<String> list = new ArrayList<>();后面的<String>,可以省略String。
  10. String对象与字符字面量的equals,可以使用java.util.Objects#equals方法
  11. 对于 Integer var = ? 在-128 至 127 范围内的赋值, Integer 对象是在IntegerCache.cache 产生,会复用已有对象,这个区间内的 Integer 值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,推荐使用 equals 方法进行判断



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值