20210625第一次面试总结

声明:本博客为本人的个人学习笔记,内容均由网上资源整理而来,若有内容错误,欢迎指正,若有侵权,立即删除。

1.系统平台如何设计,可以支持后续业务扩展

待补充

2.什么是多态,实现多态的机制,为什么要使用多态,多态的应用。

正式回答:

  • 多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
  • 多态的实现机制:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
  • 为什么要使用多态:消除类型之间的耦合关系。
  • 多态的应用:可以用在方法的参数中和方法的返回类型中。
  • 实现多态的必要条件:
    一、要有继承;
    二、要有重写或重载;(重载也算多态!!!是静态多态,是编译时期的一种多态
    三、父类引用指向子类对象。

下面开始说人话:

  • 多态就是在定义时不明确引用指向那个具体的类型(一般指向父类),在运行时才明确具体指向(具体指向哪个子类)。

    举个例子:

歌曲类,有两个子类,中文歌,英文歌
父类:歌曲类:
public class Song {
    public void printText() {
        System.out.println("唱歌");
    }
}
子类1:中文歌
public class ChineseSong extends Song {
    @Override
    public void printText() {
        System.out.println("唱中文歌");
    }
}
子类2:英文歌
public class EnglishSong extends Song {
    @Override
    public void printText() {
        System.out.println("唱英文歌");
    }
}

persion类有个方法唱歌[Sing()]

示范一:没有使用多态
 当前业务要求需要人类唱中文歌,则需这样定义persion类

public class Persion {
    public void sing(ChineseSong cheineseSong ) {
       cheineseSong.printText();
    }
}

 若干天后业务变化,需要人类唱英文歌,则需将persion类改为

public class Persion {
    public void sing(EnglishSong englishSong ) {
       englishSong .printText();
    }
}

 此时,随着业务变化,程序员需要不停的改动persion类来适配当前业务。

示范二:使用了多态

public class Persion {
    public void sing(Song song) {
       song.printText();
    }
}

  在定义sing() 方法时,将歌曲类的父类传入,并没有指定是哪个具体的子类。在业务发生变化时,只需在调用时再传入具体的Song子类即可,若有新的需求,例如唱韩文歌,只需创建新的类,继承Song,然后即可传入即可,在这期间并不需要对Persion类做修改,实现解耦。

3.什么是向上转型,向下转型,有什么作用

  • 向上转型:把子类对象直接赋给父类引用叫upcasting向上转型,向上转型不用强制转换
  • 向下转型:把指向子类对象的父类引用赋给子类引用叫向下转型(downcasting),要强制转换
  • 向上转型的作用:多态即运用了向上转型,提高代码的可复用性。
  • 向下转型的作用:向上转型会丢失子类独有的方法,可以通过向下转型再次获取。

举个例子:有2个类,Father 是父类,Son 类继承自 Father。

Father f1 = new Son();   // 这就叫 upcasting (向上转型)
Son s1 = (Son)f1;   // 这就叫 downcasting (向下转型)

注意:直接使用子类对象的引用指向父类对象,是错的,并不是向下转型
Father f2 = new Father();
Son s2 = (Son)f2;       // 出错,子类引用不能直接指向父类对象

使用向上转型时,会丢失子类中独有的方法。例如:

父类:
public class Animal {
   
    public void eat(){
      System.out.println("animal eatting...");
    }
}


子类:
class Bird extends Animal{
    
    public void eat(){
     System.out.println("bird eatting...");
   }
   
   public void fly(){
     System.out.println("bird flying...");
   }
 }


 测试类:
 class Main{
    public static void doEat(Animal h) {
     h.eat();
   }
   public static void main(String[] args) {
     
     Animal b=new Bird(); //向上转型
     b.eat();  //! error: b.fly(); b虽指向子类对象,但此时丢失fly()方法
	 //可通过向下转型的方式再次获取
	 Bird b2 = (Bird)b;
	 b2.fly();
	
     Animail c1=new Animal();
     Bird c2=new Bird();
     doEat(c1);
     doEat(c2);//此处参数存在向上转型
   }
 }

4.字节流和字符流的区别 ,实际使用中哪种更好一些。

  • 区别:

1、字节流在操作的时候本身是不会用到缓冲区(内存)的,是与文件本身直接操作的,而字符流在操作的时候是使用到缓冲区的

2、字节流在操作文件时,即使不关闭资源(close方法),文件也能输出,但是如果字符流不使用close方法的话,则不会输出任何内容,说明字符流用的是缓冲区,并且可以使用flush方法强制进行刷新缓冲区,这时才能在不close的情况下输出内容

3、Reader类的read()方法返回类型为int :作为整数读取的字符(占两个字节共16位),范围在 0 到 65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1
inputStream的read()虽然也返回int,但由于此类是面向字节流的,一个字节占8个位,所以返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。因此对于不能用0-255来表示的值就得用字符流来读取!比如说汉字.

4、字节流与字符流主要的区别是他们的的处理方式
  字节流:处理字节和字节数组或二进制对象;
  字符流:处理字符、字符数组或字符串。

  • 哪种更好:所有的文件在硬盘或在传输时都是以字节的方式进行的,包括图片等都是按字节的方式存储的,而字符是只有在内存中才会形成,所以在开发中,字节流使用较为广泛。

5.IOC的理解,为什么要IOC,IOC是如何实现的。

  • IOC的理解:传统JavaSE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;由我们自己在对象中主动控制去直接获取依赖对象变为由容器来帮忙创建及注入依赖对象,称为控制反转。
  • 为什么要IOC:实现组件之间的解耦,提高程序的灵活性和可维护性。
  • IOC的实现
    1 通过xml配置文件实现
      1.1 通过xml的简单实现
User类定义
public class User {
   
}
xml文件中配置bean
<bean id="user" class="com.User"/>
对User的使用
public class Test {
 
	public static void main(String[] args) {
		//这里还可以直接使用顶级接口BeanFactory
		ApplicationContext context = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
		//按类型获取by type
		User user1 = context.getBean(User.class);
		//按名称获取by name(在配置文件中,我们将bean声明为了user)
		User user2 = (User) context.getBean("user");

	}
}

   1.2  依赖注入

    1.2.1 接口注入:
    1.2.2  Setter注入:基于JavaBean的set()方法为属性赋值。在实际开发中得到了最广泛的应用。

配置文件
<bean id="user" class="com.User">
		<property name="name" value="张三"/>
		<property name="age" value="20"/>
</bean>
测试类
public class Test {
 
	public static void main(String[] args) {
		//这里还可以直接使用顶级接口BeanFactory
		ApplicationContext context = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
		//按类型获取by type
		Mybatis user= context.getBean(User.class);
		System.out.println(user.getName());
		System.out.println(user.getAge());
	}
}

    1.2.3 构造器注入:基于构造方法为属性赋值,容器通过调用类的构造方法,将其所需的依赖关系注入其中。

配置文件
注意:这里要和构造方法的参数顺序一致,否则会产生异常
<bean id="user" class="com.User">
		<constructor-arg value="张三"/>
		<constructor-arg value="李四"/>
</bean>
测试类 和上面的Setter测试没有区别
public class Test {
 
	public static void main(String[] args) {
		//这里还可以直接使用顶级接口BeanFactory
		ApplicationContext context = new FileSystemXmlApplicationContext("classpath:applicationContext.xml");
		//按类型获取by type
		Mybatis user= context.getBean(User.class);
		System.out.println(user.getName());
		System.out.println(user.getAge());
	}
}

2 通过注解实现

实体类定义
public class User {
 
	private String name;
	
	private String age;
	
	//省略set/get和构造方法
}
@Configuration注解的配置文件,作用相当于xml配置文件
@Configuration
public class AppConfig {
 
	@Bean(name="user")
	public User initUser() {
		User user = new User();
		user.setName("zepal");
		user.setAge("18");
		return user;
	}
}
测试类
public class Test {
 
	ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		User user = (User) context.getBean("user");
	
}

ps:
通过扫描装配Bean,一般使用@Component+@ComponentScan组合。
@Component用于标记哪个类被扫描进IoC,@ComponentScan则是标明采用哪种策略去扫描装配Bean。类似于XML中的context:component-scan标签。
@Component可以指定Bean的名称,如果不指定,则按照类型首字母小写作为Bean的名称,byName获取的时候注意。@ComponentScan默认扫描当前包或其子包,所以一般在springboot项目中,所有包都是启动包的子包,@SpringBootApplication启动注解,在1.5之后包含了@ComponentScan注解,所以在SpringBoot中不单独指定。所以像我们的服务层用的@Service注解才会被扫描注册为Bean,@Service里也涵盖了@Component注解。
@ComponentScan在指定扫面包的时候可以采用通配符,还有一些其他功能比如过滤器,指定不扫描哪些包等等。

6.怎么理解反射,为什么要反射,哪些地方用到了反射

  • 反射的定义:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的以及动态调用对象的方法的功能称为java语言的反射机制。
  • 为什么要用反射:提高代码的可复用性,避免将代码写死。例如:外卖平台有支付接口,又有几个支付接口的实现类,支付宝、微信。在用户点击支付之前,平台无法获知到底使用哪个支付实现类。故采用反射,避免将支付代码写死,利用反射,按照用户端选择的支付方式,动态的创建具体支付类,调用支付方法。

例如:

支付接口
interface Pay() {
	private void pay();
}
具体支付实现类:支付宝
Class AliPay() {
	@Override
	private void pay(){
		sout("调用支付宝");
	}
}
具体支付实现类:微星
Class WeChatPay() {
	@Override
	private void pay(){
		sout("调用微信");
	}
}
业务中具体的支付调用方法
type为客户端传过来的支付方式,例如为:"com.AliPay"或是"com.WeChatPay"(为AliPay或WeChatPay的类全名)。
public void realPay(String type) {
	Class cls= Class.forName(type);//依据类全名获取class
	Object o = cls.newInstance();//新建类
	Method mothod = cla.getMethod("pay");//获取类方法
	mehtod.invoke(o);//调用类方法
}

  具体的支付调用方法中,并没有写死调用哪个类的方法,而是在动态过程中依据参数,动态的创建类,调用对应的方法。在业务变化时提高了代码的复用性。

7.MVC的相关注解,以及作用

注解作用位置作用
@RequestBody方法上主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的),GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。
@ResponseBody方法上将controller的方法返回的对象通过适当的转换器转换为指定的格式之后,写入到response对象的body区,通常用来返回JSON数据或者是XML数据。
@Controller类上此注解使用在class上声明此类是一个Spring controller。
@RestController类上相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面
@RequestParam方法参数之前该注解的作用是把请求中指定名称的参数给控制器中的形参赋值。其中该注解有两个属性:value:请求参数中的名称。required:请求参数中是否必须提供此参数。默认值:true。表示必须提供,如果不提供将报错。
@PathVariable(“xxx“)方法上通过 @PathVariable 可以将URL中占位符参数{xxx}绑定到处理器类的方法形参中@PathVariable(“xxx“)使用说明,截取自https://blog.csdn.net/sswqzx/article/details/84194979
@RequestMapping类上或是方法上是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。

8.如何理解泛型,为什么使用泛型

  • 什么是泛型:“泛型” 意味着编写的代码可以被不同类型的对象所重用。泛型的提出是为了编写重用性更好的代码。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
  • 为什么使用泛型:为了数据安全、提高程序的性能
      1.数据安全:若是没有泛型,默认的都为Object类型,假如放了一个 Integer使用时却要把他转化为String,这个在代码编写时不会报错,但是在运行时会报错,不安全。
      2.提高性能:若是没有泛型,默认的都为Object类型,在使用时需要进行Object向其他类型的转化,会有大量的装箱、拆箱操作,降低性能程序的性能。

9.二十三种设计模式

博客园:JAVA设计模式总结之23种设计模式

参考引用文档:
百度知道:java里,方法重载是不是多态的一种实现?
CSDN:字符流与字节流的区别
博客园:谈谈对springIoc的理解
CSDN:SpringMVC基础中常用注解及其作用
CSDN:@PathVariable注解使用
CSDN:@RequestBody的使用
博客园:为什么要用泛型呢
深入理解什么是Java泛型?泛型怎么使用?
博客园:Java 转型问题(向上转型和向下转型)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值