基础面试题之基础(一)"/>
Java基础面试题之基础(一)
什么是面向对象?
面向对象是一种编程思想.Java是一个支持高并发,基于类和面向对象的计算机编程语言.
面向对象的优点:
- 使代码开发更加模块化,利于维护和修改
- 代码复用性强.
- 增强代码的可靠性和灵活性.
- 增强代码的可读性
请说说面向对象的特征?
封装
给对象提供隐藏内部特性和行为的能力.对象提供一些能被其他对象访问的方法来改变和获取内部数据.
public class Man {private String name;private String age;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAge() {return age;}public void setAge(String age) {this.age = age;}}
在Java中有4种修饰符:default,public,private,protected.每种修饰符给其他的位于同一个包或者不同包的对象赋予不同的访问权限.
以上面的代码为例:Man类有两个private属性,private访问修饰符的访问权限只有在本类中才能够访问,在其他类中是访问不了的,这就叫做隐藏内部特性,而外部想要获取属性的值的话只能通过GetXXX方法,如果想改变内部数据的值的话使用SetXXX方法.
封装的好处
- 通过隐藏对象的属性来保护对象的内部状态
- 提高了代码的可用性和可维护性,因为对象的行为可以被单独改变或扩展.
- 禁止对象之间的不良交互提高模块化
继承
继承,给对象提供了从基类获取字段和方法的能力。继承提供了代码的重用性,也可以在不修改类的情况下给现存的类添加新特性。
拿我的实际项目举个例子:
这是个基类,基类(有时候又称父类)中有两个静态常量
@Component
public class BasicController {@Autowiredpublic RedisOperator redisOperator;//分页查询时没页显示的数量public static final Integer PAGE_SIZE = 5;public static final String ADMIN_USER_REDIS_SESSION = "AdminUser-Redis-Session";}
这是个子类,子类能够直接使用基类的字段.
@Controller
@RequestMapping(“users”)
public class UsersController extends BasicController {
/*注销*/
@GetMapping("/logout")
public String logout(HttpServletRequest request, HttpServletResponse response, String userId) {request.getSession().removeAttribute("sessionUser");redisOperator.del(ADMIN_USER_REDIS_SESSION + ":" + userId);return "login";
}
多态
多态,是编程语言给不同的底层数据类型做相同的接口展示的一种能力。一个多态类型上的操作,可以应用到其他类型的值上面。
多态的最常见用法:父类引用指向子类对象
public interface Vegetarian{};public class Animal{};public class Dog extends Animal implements Vegetarian{Dog d = new Dog();// 父类引用指向子类对象Animal a = d;Vegetarian v = d;Object o = d;//所有的引用变量(d,a,v,o)都指向了堆中的同一个对象Dog};
抽象
抽象,是把想法从具体的实例中分离出来的步骤,因此,要根据他们的功能而不是实现细节来创建类。
Java 支持创建只暴漏接口而不包含方法实现的抽象的类。这种抽象技术的主要目的是把类的行为和实现细节分离开。
项目举例
接口
public interface IVideoService {/*将视频信息保存到数据库*/public String saveVideo(Videos videos);}
实现类
package chen.services.impl;/*视频相关接口实现类*/@Servicepublic class VideoServiceImpl implements IVideoService {@Transactional(propagation = Propagation.REQUIRED)@Overridepublic String saveVideo(Videos videos) {String id = sid.nextShort();videos.setId(id);videosMapper.insertSelective(videos);return id;}}
面向对象和面向过程的区别?
面向过程
- 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源。比如,单片机、嵌入式开发、Linux/Unix 等一般采用面向过程开发,性能是最重要的因素。
- 缺点:没有面向对象易维护、易复用、易扩展。
面向对象
- 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护。
- 缺点:性能比面向过程低。
重载和重写的区别?
重写
- 方法名、参数、返回值相同。
- 子类方法不能缩小父类方法的访问权限。
- 子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
- 存在于父类和子类之间。
- 方法被定义为 final 不能被重写。
普通方法重写
package method.override;/**
* @program: InterviewQuestion
* @description: 父类
* @author: Mr.Wang
* @create: 2019-07-28 16:34
**/
public class Parent {private String name;public void move() {System.out.println("张三喜欢小花");}
}--------------------------------------------package method.override;/**
* @program: InterviewQuestion
* @description: 子类
* @author: Mr.Wang
* @create: 2019-07-28 16:34
**/
public class Child extends Parent {private Integer age;public void move() {System.out.println("李四喜欢小翠");}
}--------------------------------------------package method.override;/**
* @program: InterviewQuestion
* @description: Main类
* @author: Mr.Wang
* @create: 2019-07-28 16:36
**/
public class Main {public static void main(String[] args) {Parent parent = new Parent();parent.move();Child child = new Child();child.move();}
}
子类方法不能缩小父类方法的访问权限
public class Parent {private String name;protected void move() {System.out.println("张三喜欢小花");}
}public class Child extends Parent {
private Integer age;public void move() {System.out.println("李四喜欢小翠");
}
}public class Main {
public static void main(String[] args) {Parent parent = new Parent();parent.move();Child child = new Child();child.move();
}
}
方法被定义为 final 不能被重写。
public class Parent {private String name;protected final void move() {System.out.println("张三喜欢小花");}}public class Child extends Parent {private Integer age;public void move() {System.out.println("李四喜欢小翠");}
}
无法重写静态方法
public class Parent {private String name;static void move() {System.out.println("父类的move方法");}public void m2(){System.out.println("父类的m2方法");}}public class Child extends Parent {private Integer age;static void move() {System.out.println("子类的move方法");}public void m2(){System.out.println("子类的m2方法");}}public class Main {public static void main(String[] args) {Parent parent = new Child();parent.move();parent.m2();}
}
在重写和异常处理时需要注意以下两个规则:
如果基类方法不抛出异常,子类重写的方法只能抛出未检查异常,抛出已检查异常会导致编译错误
public class Parent {private String name;public void m1() {System.out.println("父类的move方法");}public void m2(){System.out.println("父类的m2方法");}}public class Child extends Parent {private Integer age;public void m1() throws ArithmeticException {System.out.println("子类的move方法");}//编译错误public void m2() throws Exception{System.out.println("子类的m2方法");}}
如果基类重写方法确实抛出异常,则子类重写方法只能抛出相同的子类异常。在异常层次结构中抛出父异常将导致编译时错误。如果子类重写方法没有抛出任何异常,也没有问题。
class Parent
{ void m1() throws RuntimeException { System.out.println("From parent m1()");} } class Child1 extends Parent
{ @Override// 抛出相同的异常没有问题 void m1() throws RuntimeException { System.out.println("From child1 m1()");} }
class Child2 extends Parent
{ @Override// 抛出子类异常也没有问题void m1() throws ArithmeticException { System.out.println("From child2 m1()");} }
class Child3 extends Parent
{ @Override// 不抛出异常也没有问题void m1() { System.out.println("From child3 m1()");} }
class Child4 extends Parent
{ @Override// 编译错误,抛出的异常超出了父类的异常void m1() throws Exception { System.out.println("From child4 m1()");}
}
重载(overload)
- 参数类型、个数、顺序至少有一个不相同。
- 不能重载只有返回值不同的方法名。
- 存在于父类和子类、同类中。
普通重载
public class Sum { //两个参数public int sum(int x, int y) { return (x + y); } //三个参数public int sum(int x, int y, int z) { return (x + y + z); } //两个double类型的参数,且返回值和前两个sum不一样public double sum(double x, double y) { return (x + y); } public static void main(String args[]) { Sum s = new Sum(); System.out.println(s.sum(10, 20)); System.out.println(s.sum(10, 20, 30)); System.out.println(s.sum(10.5, 20.5)); }
}
main方法能够被重载吗?
import java.io.*;public class Main {// Normal main()public static void main(String[] args) {System.out.println("Hi Geek (from main)");Main.main("Geek");}// Overloaded main methodspublic static void main(String arg1) {System.out.println("Hi, " + arg1);Main.main("Dear Geek", "My Geek");}public static void main(String arg1, String arg2) {System.out.println("Hi, " + arg1 + ", " + arg2);}}
可以重载静态方法吗?
可以,两个名字相同但是参数列表不一定相同的方法.
方法重载的优点是什么?
不需要为做相同事情的函数创建和记住不同的名称。例如,在我们的代码中,如果Java不支持重载,我们将不得不创建像sum1、sum2、…或sum2Int、sum3Int等方法名。
可以按照返回类型重载方法吗?
不能.
public class Main { public int foo() { return 10; } // compiler error: foo() is already defined public char foo() { return 'a'; } public static void main(String args[]) { }
}
总结
Java中,什么是构造方法?什么是构造方法重载?什么是拷贝构造方法?
构造方法
当新对象被创建的时候,构造方法会被调用。每一个类都有构造方法。在程序员没有给类提供构造方法的情况下,Java 编译器会为这个类创建一个默认的构造方法。
public class Man {private String name;private Integer Money;private Boolean HaveAGirl; //是否有女朋友public Man() {System.out.println("我是一个男人");}
}public class Main {public static void main(String[] args) {Man man = new Man();}
}
构造方法重载
Java 中构造方法重载和方法重载很相似。可以为一个类创建多个构造方法。每一个构造方法必须有它自己唯一的参数列表。
public class Man {private String name;private Integer money;private Boolean haveAGirl; //是否有女朋友public Man() {System.out.println("我是一个男人");}public Man(String name, Integer money) {System.out.printf("名字%s,金钱%d,", name, money);System.out.println();}public Man(Integer money, String name) {System.out.printf("金钱%d,名字%s", money, name);System.out.println();}public Man(String name, Integer money, Boolean haveAGirl) {System.out.printf("名字%s,金钱%d,是否有女朋友%b", name, money, haveAGirl);}
}
public class Main {public static void main(String[] args) {Man man = new Man();Man man1 = new Man("高富帅", 200000);Man man2 = new Man(200000, "公子哥");Man man3 = new Man("土豪", 20000000, true);}
}
拷贝构造方法
Java 不支持像 C++ 中那样的拷贝构造方法,这个不同点是因为如果你不自己写构造方法的情况下,Java 不会创建默认的拷贝构造方法。
class Complex { private double re, im; // 含参构造函数public Complex(double re, double im) { this.re = re; this.im = im; } // 构造函数拷贝 Complex(Complex c) { System.out.println("调用被拷贝的构造函数"); re = c.re; im = c.im; } @Overridepublic String toString() { return "(" + re + " + " + im + "i)"; }
} public class Main { public static void main(String[] args) { Complex c1 = new Complex(10, 15); // 构造函数的调用 Complex c2 = new Complex(c1); // 构造函数的调用// 非原始变量仅引用Complex c3 = c2; System.out.println(c2); }
}
更多推荐
Java基础面试题之基础(一)
发布评论