Java面试题分享0519

目录

1、重载和重写区别?

2、构造器(Constructor)是否可被重写(override)

3、break 、continue 、return 作用?

4、JAVA 创建对象有哪些方式?

5、== 和 equals 有什么区别?

6、Integer 和 int 有什么区别?


1、重载和重写什么区别?

定义与范围:

  • 重载:在同一个类中,可以有多个同名但参数列表不同的方法。这样的方法被称为重载方法。重载是编译时的多态性的一种表现,它允许类以统一的方式处理不同类型的数据。
  • 重写:在面向对象编程中,子类可以重新定义父类中已有的方法,这被称为重写。重写是子类与父类之间的一种关系,允许子类根据自身的需求修改父类中的方法实现。

参数与多态性:

  • 重载:重载方法的参数个数、参数类型或参数的顺序可以不同。返回值类型可以相同,也可以不相同。重载的参数列表必须不同,否则编译器会报错。
  • 重写:子类重写父类的方法时,方法名、参数列表和返回类型必须与父类中被重写的方法相同。重写是运行时的多态性的一种表现,子类对象在调用方法时会根据实际类型来确定调用哪个版本的方法。

修饰符与访问权限:

  • 重载:重载方法对修饰符和访问权限没有特定要求。
  • 重写:重写方法的访问权限不能低于被重写方法的访问权限。例如,如果父类中的方法是public的,那么子类中的重写方法也必须是public的。此外,重写方法的异常处理也不能比被重写方法的异常处理更严格。

功能与目的:

  • 重载:通过提供多个具有不同参数列表的同名方法,可以使类更加灵活和易于使用。重载方法可以根据传入的参数类型或数量来执行不同的操作。
  • 重写:通过子类重写父类的方法,可以实现对父类功能的修改或扩展。重写方法允许子类根据自身的需求重新定义父类中的方法实现,从而实现多态性。这有助于在面向对象编程中实现代码的复用和扩展性。

举例:

  • 重载(Overloading):在同一类中定义多个同名但参数列表不同的方法
public class OverloadExample {  
  
    // 第一个版本的print方法,没有参数  
    public void print() {  
        System.out.println("No parameters");  
    }  
  
    // 第二个版本的print方法,接受一个整数参数  
    public void print(int i) {  
        System.out.println("Integer parameter: " + i);  
    }  
  
    // 第三个版本的print方法,接受一个字符串参数  
    public void print(String s) {  
        System.out.println("String parameter: " + s);  
    }  
  
    public static void main(String[] args) {  
        OverloadExample example = new OverloadExample();  
        example.print();        // 调用无参数的print方法  
        example.print(10);      // 调用接受整数参数的print方法  
        example.print("Hello"); // 调用接受字符串参数的print方法  
    }  
}
  • 重写(Overriding):

子类可以重写父类的方法。当子类对象调用这个方法时,会执行子类中的实现:

class Animal {  
    // 父类中的方法  
    public void makeSound() {  
        System.out.println("The animal makes a sound");  
    }  
}  
  
class Dog extends Animal {  
    // 子类重写父类中的方法  
    @Override // 这个注解是可选的,但建议使用以明确表示我们正在重写父类的方法  
    public void makeSound() {  
        System.out.println("The dog barks");  
    }  
}  
  
public class OverridingExample {  
    public static void main(String[] args) {  
        Animal myAnimal = new Animal();  
        myAnimal.makeSound(); // 输出 "The animal makes a sound"  
  
        Dog myDog = new Dog();  
        myDog.makeSound(); // 输出 "The dog barks"  
  
        // 向上转型,但仍然调用子类的重写方法  
        Animal myPet = new Dog();  
        myPet.makeSound(); // 输出 "The dog barks",因为实际对象是Dog类型  
    }  
}

例子中,Dog类继承了Animal类,并重写了makeSound方法。当创建Dog对象并调用makeSound方法时,会执行Dog类中的实现。同时,由于Java支持向上转型(将子类对象赋值给父类引用),所以即使将Dog对象赋值给Animal类型的引用,调用makeSound方法时仍然会执行Dog类中的实现。

2、构造器(Constructor)是否可被重写(override)

不能。这是因为构造器不是类的方法,而是用于初始化对象的状态的特殊方法。在Java中,重写(overriding)是指子类提供一个与父类方法签名完全相同的方法的行为,但构造器的签名包括类名,这是唯一的,因此子类不能有一个与父类完全相同的构造器签名。

然而,子类可以定义自己的构造器,这些构造器通常会调用父类的构造器(使用super关键字)来确保父类中的初始化代码被执行。如果子类没有显式地调用父类的构造器,编译器会默认调用父类的无参构造器(如果父类中存在的话)。

子类构造器如何调用父类构造器的例子:

class Parent {  
    public Parent() {  
        System.out.println("Parent's constructor called");  
    }  
  
    public Parent(String message) {  
        System.out.println("Parent's constructor with message called: " + message);  
    }  
}  
  
class Child extends Parent {  
    public Child() {  
        // 隐式调用父类的无参构造器  
        super(); // 可以显式调用,但在这个例子中是多余的  
        System.out.println("Child's constructor called");  
    }  
  
    public Child(String message) {  
        // 显式调用父类带有一个字符串参数的构造器  
        super(message);  
        System.out.println("Child's constructor with message called");  
    }  
}  
  
public class ConstructorExample {  
    public static void main(String[] args) {  
        Child child1 = new Child(); // 输出 Parent's constructor called 和 Child's constructor called  
        Child child2 = new Child("Hello"); // 输出 Parent's constructor with message called: Hello 和 Child's constructor with message called  
    }  
}

在这个例子中,Child类有两个构造器,一个无参构造器和一个带有一个字符串参数的构造器。这两个构造器都显式或隐式地调用了Parent类的构造器来确保父类状态被正确初始化。但是,这并不是重写构造器,而是子类构造器调用父类构造器的一种机制。 

3、break 、continue 、return 作用?

都是用于控制程序流程的关键字,但它们在用途和上下文中有所不同。break用于终止循环或switch语句,continue 用于跳过当前循环迭代,而return用于从方法中返回一个值并退出方法。

  • break:

break语句用于立即终止最内层循环(for、while、do-while)或 switch语句的执行。当break语句被执行时,程序会跳出当前的循环或switch语句,继续执行循环或switch语句后面的代码(如有)

for (int i = 0; i < 10; i++) {  
    if (i == 5) {  
        break; // 当 i 等于 5 时,跳出循环  
    }  
    System.out.println(i); // 这将打印 0 到 4  
}
  • continue:

continue语句用于跳过当前循环迭代中的剩余代码,并立即开始下一次迭代。它不会终止整个循环,而是只跳过当前迭代中的剩余代码。

for (int i = 0; i < 10; i++) {  
    if (i == 5) {  
        continue; // 当 i 等于 5 时,跳过当前迭代  
    }  
    System.out.println(i); // 这将打印 0 到 4 和 6 到 9,但不包括 5  
}
  • return:

return语句用于从方法中返回一个值,并立即结束该方法的执行。如果方法具有返回值类型(即不是void),则return语句必须返回一个与声明类型兼容的值。如果方法没有返回值(即返回类型为void),则return语句可以用于无条件地退出方法。

public int getMax(int a, int b) {  
    if (a > b) {  
        return a; // 返回较大的数并退出方法  
    } else {  
        return b; // 返回较小的数并退出方法  
    }  
}  
  
public void printGreeting() {  
    System.out.println("Hello!");  
    return; // 退出方法,但因为没有返回值类型,所以不需要返回任何值  
}

4、JAVA 创建对象有哪些方式?

在Java中,创建对象(或称为实例化对象)的主要方式有以下几种:

  • 使用new关键字

    这是最常见的方式,通过new关键字调用类的构造函数来创建一个新的对象。

    MyClass obj = new MyClass();
  • 使用反射(Reflection):通过Class对象的newInstance()方法或Constructor对象的newInstance()方法,可以在运行时动态地创建对象。这通常用于框架和插件系统等,因为可以在运行时才确定要实例化的类。注意:从Java 9开始,newInstance()方法已经被标记为废弃,应使用getDeclaredConstructor().newInstance()

    Class<?> clazz = MyClass.class;  
    MyClass obj = (MyClass) clazz.newInstance(); // 需要无参构造函数  
    
    // 或者使用Constructor  
    Constructor<?> constructor = clazz.getConstructor();  
    MyClass obj2 = (MyClass) constructor.newInstance();
  • 使用克隆(Cloning)

    如果类实现了Cloneable接口并覆盖了clone()方法,就可以通过调用clone()方法来创建一个对象的副本。

    MyClass original = new MyClass();  
    MyClass clone = (MyClass) original.clone();

    注意:clone()方法默认是保护方法(protected),因此需要在子类中才能访问,或者通过类的公有方法提供访问。

  • 使用序列化(Serialization)和反序列化(Deserialization)

    如果类实现了Serializable接口,那么就可以将对象序列化为字节流,然后再从字节流中反序列化出一个新的对象。这通常用于持久化对象或在网络中传输对象。

    ByteArrayOutputStream bos = new ByteArrayOutputStream();  
    ObjectOutputStream oos = new ObjectOutputStream(bos);  
    oos.writeObject(original); // 序列化  
    
    ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());  
    ObjectInputStream ois = new ObjectInputStream(bis);  
    MyClass deserialized = (MyClass) ois.readObject(); // 反序列化
  • 使用工厂模式(Factory Pattern)

    工厂模式是一种创建型设计模式,它封装了对象的创建过程,使用工厂方法代替new操作符来创建对象。这可以隐藏对象的创建逻辑,使得代码更加灵活和可维护。

    public class MyClassFactory {  
        public static MyClass createInstance() {  
            return new MyClass();  
        }  
    }  
    
    // 使用  
    MyClass obj = MyClassFactory.createInstance();
  • 使用建造者模式(Builder Pattern)

    建造者模式用于创建复杂对象,允许在创建对象的过程中设置多个参数。建造者模式通常包含一个建造者类和一个产品类。

    MyClass.Builder builder = new MyClass.Builder();  
    MyClass obj = builder.withParam1("value1").withParam2(42).build();
  • 使用单例模式(Singleton Pattern)

    虽然单例模式不是直接创建对象的方式,但它确保了一个类只有一个实例,并提供了一个全局访问点。在某些情况下,这可能被视为一种创建对象的方式。

    MyClass obj = MyClass.getInstance();

5、== 和 equals 有什么区别?

在Java中,都用于比较两个对象或值,但它们的用法和上下文存在显著差异

  • 基本数据类型与对象类型

    • 对于基本数据类型(byte、short、intlong、 boolean、char、float、double),== 用于比较它们的值是否相等。
    • 对于对象类型(即类的实例),== 默认用于比较两个对象的引用是否指向内存中的同一个对象(即比较的是对象的内存地址)。
  • equals() 方法

    • equals() 方法是 java.lang.Object 类中的一个方法,用于比较两个对象的内容(或称为“值相等性”)是否相等。
    • 在 Object 类中,equals() 方法的默认实现与 == 相同,即比较对象的引用是否相等。
    • 但是,许多类(如 StringIntegerDate 等)都重写了 equals() 方法,以便比较对象的内容是否相等。
    • 例如,对于 String 类型,str1.equals(str2) 将比较两个字符串的内容是否相同,而不是比较它们的引用是否相同。

6、Integer 和 int 有什么区别?

  • 数据类型int 是 Java 的一种基本数据类型(primitive data type),它用于存储 32 位有符号的二进制整数。Integer 是 Java 提供的一个对 int 类型的封装类(wrapper class),位于 java.lang 包中。它提供了许多方法来操作 int 类型的值,并且允许 int 值被当作对象来处理(例如,在集合中使用)。
  • 默认值int 类型的变量在声明时如果没有初始化,其默认值为 0。Integer 类型的对象在声明时如果没有初始化,其默认值为 null(因为 Integer 是对象类型)。
  • 内存占用int 类型的变量直接存储整数值,通常存储在栈内存中(如果作为局部变量)或对象的实例字段中(如果作为对象的属性)。Integer 对象在堆内存中分配内存,并且包含对整数值的引用(以及可能的额外开销,如对象头信息)。
  • 自动装箱和拆箱:Java 5 引入了自动装箱(autoboxing)和拆箱(unboxing)的概念,允许在基本数据类型和对应的封装类之间自动转换。例如,Integer i = 10; 会自动将 int 类型的字面量 10 装箱为 Integer 对象。同样地,int j = i; 会自动将 Integer 对象 i 拆箱为 int 类型的值。
  • 缓存:对于 -128 到 127(包括两端)之间的 Integer 对象,Java 使用了缓存机制,即当创建这些范围内的 Integer 对象时,实际上返回的是对同一个对象的引用。这可以通过 Integer.valueOf(int i) 方法来看到,该方法对于上述范围内的值会返回缓存中的对象,而对于其他值则会创建新的对象。
  • 可空性:由于 int 是基本数据类型,它不能是 null。但是,Integer 作为对象类型,可以是 null
  • 方法Integer 类提供了许多有用的方法,如 parseInt(String s) 用于将字符串转换为整数,compareTo(Integer anotherInteger) 用于比较两个 Integer 对象的值等。而 int 类型则没有这些方法。
  • 性能:在大多数情况下,使用基本数据类型 int 比使用 Integer 对象更高效,因为 int 类型的变量不需要额外的内存开销和对象管理开销。然而,在需要将整数作为对象处理(如在集合中使用)的场景下,使用 Integer 是必要的。

在性能敏感的场景下,优先考虑使用 int;在需要将整数作为对象处理的场景下,使用Integer

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值