【Java SE】SE语法备忘(2)(Spring Boot + IOC + OOP)

本文围绕Spring框架和OOP特性展开。介绍了Spring的控制反转、依赖注入等核心概念,包括Bean的作用域、生命周期及配置方式。还阐述了OOP的封装、继承、多态等特性。此外,涵盖了Spring Boot的常见问题,如配置文件、注解、启动方式等,以及枚举、Scanner和Servlet相关知识。

【Java SE】SE语法备忘(1)
https://mp.youkuaiyun.com/postedit/86519812

Spring

Spring是为了解决企业应用开发的复杂性而创建的一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
在这里插入图片描述
Spring设计理念:
Spring是面向Bean的编程;

Spring两大核心技术:

  • IoC 控制反转/依赖注入
  • AOP 面向切面编程

————————————————————————————————
BeanIoC中所有对象都叫Bean

Bean的配置方式:有三种

  • 1.XML配置
  • 2.注解配置(用得最多)
  • 3.Java类的配置

XML:
在这里插入图片描述

举例:

public class UserServiceImpl implements UserService{
    private UserDao userdao = new UserDao();
}

改成

public class UserServiceImpl implements UserService{
    @Autowired
    private UserDao userdao;
}

Spring 的 IoC 设计支持以下功能:

  • 依赖注入(最重要)
  • 依赖检查
  • 自动装配
  • 支持集合
  • 指定初始化方法和销毁方法
  • 支持回调某些方法(但是需要实现 Spring 接口,略有侵入)

其中,最重要的就是依赖注入,从 XML 的配置上说, 即 ref 标签。对应 Spring RuntimeBeanReference 对象。

对于 IoC 来说,最重要的就是容器。容器管理着 Bean 的生命周期,控制着 Bean 的依赖注入。
那么, Spring 如何设计容器的呢?

Spring 设计了两个接口用以表示容器。

  • BeanFactory :低级容器
  • ApplicationContext :高级容器

BeanFactory 粗暴简单,可以理解为就是个 HashMap,Key 是 BeanName,Value 是 Bean 实例。通常只提供注册(put),获取(get)这两个功能。我们可以称之为 “低级容器”。
ApplicationContext 可以称之为 “高级容器”。因为他比 BeanFactory 多了更多的功能。他继承了多个接口。因此具备了更多的功能。
————————————

DI 依赖注入

DI 依赖注入
是IoC的一种实现方式
在IoC容器在运行期间,动态地将某种依赖关系注入到对象之中;
(在启动Spring容器加载bean配置的时候,完成对变量的赋值行为)

讲白话:
IoC容器在加载时,会自动扫描相关配置,对这些Bean进行实例化;
注入是:实例化过程中完成对成员变量的赋值;
比如:在A类中引用B类,声明了一个B类对象,注入是在IoC初始化A类时就把A的成员变量B进行了赋值;

IoC和DI之间的关系:
创建对象并且组装对象之间的关系;

常用的注入方式:2种

  • 1.设值注入
  • 2.构造注入

在这里插入图片描述
在这里插入图片描述

——————————————
例1:
https://www.cnblogs.com/GenghisKhan/p/3540131.html

某公司新成立了一个Team,Team中有成员和一个组长;
小李是组长;

这个例子的目的:将Team和组长解耦;

版本1

    public class Li{
        public void intro(){
            System.out.println("大家好,我是小李。");
        }
    }
    public class Team{
        public void firstIntro(){
            Li li = new Li();
            li.intro();
        }
    }

上述代码基本完成了相关需求;
但上述代码是根据具体的场景描述进行的,没有进行抽象,这样就导致我们不能灵活的安排项目组长去做开场;
即根据现在的代码,组长的自我介绍不能安排给其他人;
为了解决上述的问题,我们引入首先引入Leader接口

    public interface Leader{
        public void intro();
    }

    public class Li implements Leader{
        @Override
        public void intro() {
            System.out.println("大家好,我是小李。");
        }
    }

    public class Team{
        public void firstIntro(){
            Leader leaderLi = new Li();
            leaderLi.intro();
        }
    }

上述代码虽然可以让我们安排给其他成员开场,但是看得出:
Team类同时依赖Leader接口Li类
并没有达到我们所期望的Team仅仅依赖于Leader接口的目的;
如何解决这个问题?这时需要引入IoC思想:
当然是引入Boss,由Boss决定具体由谁担任项目组长:

    public interface Leader{
        public void intro();
    }

    public class Li implements Leader{
        @Override
        public void intro() {
            System.out.println("大家好,我是小李。");
        }
    }

    public class Team{
        public void firstIntro(Leader leader){
            leader.intro();
        }
    }
    
    public class Boss{
        public void direct(){
            Team team = new Team();
            Leader leaderLi = new Li();
            team.firstIntro(leaderLi);
        }
    }

通过以上代码,我们可以看出,通过引入Boss类,我们将:
“ Team 和 组长 ” 进行了解耦。

对应上述例子,我们再来讲解一下IoC,IoC从字面上看分为控制和反转;
控制 在上面的实例中就是:组长决定权;(本来在:Team类)
反转 就是将 组长决定权 转移到Boss类中;(转移到第三方:Boss类)
通俗理解就是将接口的具体实现类(Li)的控制权,从调用类(Team)中,分离转交给第三方(Boss)决定。


IoC这种解决依赖的方法是面向对象方法的使用;
现实世界中,这种方法无处不在。
比如,汽车不会强依赖于某个品牌的轮胎,任何公司生产的轮胎,只要符合汽车的接口,就可以装在这个汽车上使用。
还有电脑的USB接口,只要符合USB标准的外设,就都能够接上电脑使用。

解除依赖不仅让代码结构看起来更加合理,其带来的另一个好处是:
各个部分可以单独的做单元测试,使得单元测试能够更加容易的进行。
这个对于一些复杂度高的项目,对于保证项目的稳定性和可用性非常有意义。

那我们使用IOC能达到什么呢?
IOC,就是DAO接口的实现不再是业务逻辑层调用工厂类去获取,而是通过容器(比如spring)来自动的为我们的业务层设置DAO的实现类。
这样整个过程就反过来,以前是我们业务层主动去获取DAO,而现在是DAO主动被设置到业务逻辑层中来了,这也就是反转控制的由来。
通过IOC,我们就可以在不修改任何代码的情况下,无缝的实现数据库的换库迁移,当然前提还是必须得写一个实现特定数据库的DAO。
我们把DAO普遍到更多的情况下,那么IOC就为我们带来更大的方便性,比如一个接口的多个实现,我们只需要配置一下就ok了,而不需要再一个个的写工厂来来获取了。
这就是IOC为我们带来的模块的松耦合和应用的便利性。

Bean的作用域

若没有为Bean添加scope(作用域),程序默认他为单例模式;

https://www.imooc.com/learn/1108
在这里插入图片描述
Singleton:单例模式
<bean class = "......" id = "bean..." scope = "singleton"/>
在同一个上下文环境中!!!(单例模式的局限性),每次向Spring上下文中请求此Bean的实例时,Spring都会返回同一个实例;
(或者:整个Spring上下文生命周期中只存在一个实例)

(要强调同一个上下文环境,因为若出现了多个上下文环境,每个环境中都是单例模式;单个上下文环境中的实例都是一样的,但不同上下文环境中返回的实例会不同)
在这里插入图片描述
Prototype:
<bean class = "......" id = "bean..." scope = "prototype"/>
每次向Spring上下文中请求实例时,拿到的都是一个全新的实例;
在这里插入图片描述
实战的前提:
要有spring-core spring-context junit 包;
————————————————
试一试:
若Bean1和Bean2有依赖关系,Bean1包含一个属性:Bean2;
若他们采取不同模式进行组合:
分别输出他们的context.getBean,比较他们是否相等,他们会否相等?

Bean1单例 & Bean2单例:true (两个B1中的B2相同,因为B2单例)
Bean1单例 & Bean2多例:true (两个B1中的B2相同)
(因为B1单例,只有唯一实例化;尽管B2多例,但是因为B1只有一个实例,所以B2只需要被实例化一次)
Bean1多例 & Bean2单例:false (两个B1中的B2相同)
(两个B1实例是不同的,自然返回false)
Bean1多例 & Bean2多例:false (两个B1中的B2不同)

在这里插入图片描述

Bean生命周期

1.Bean初始化
2.Bean销毁

————————
1.Bean初始化

两种方法:

  • (1).使用init-method
  • (2).让Bean实现InitializingBean接口

————————
2.Bean销毁

两种方法:

  • (1).使用destroy-method
  • (2).让Bean实现DisposableBean接口

————————
若采取XML方式:

<bean class="........."
    init-method="初始化的方法名" destroy-method="销毁的方法名"
    id="bean"/>

————————————————

使用注解方式配置IoC

在这里插入图片描述
在这里插入图片描述
若有@Configuration,则可以通过AnnotationConfigurationApplicationContext这个类把它变成一个Spring上下文环境;
MyConfiguration类中,有加了@Bean的方法;
————————————————

IoC面试题

提问:Spring中Bean 的生命周期是怎么样的?

Spring中Bean的生命周期从大方面讲是:
定义创建实例 —— 初始化 —— 使用 —— 销毁
Spring在初始化后BeanFactory实例化后,就加载Bean定义(xml配置、注解或Java配置文件)配置,依次生成每个类对应Bean的单例对象,然后填充对象属性
(包括注入依赖对象,此时若依赖对象还没创建,会尝试先创建并初始化依赖Bean对象后再继续当前bean实例的初始化)
然后开始bean对象的初始化,此处用户可以通过@PostConstruct、继承InitializingBean类或指定init-method的方法自定义自己的初始化方法
(如果上面上个方法同时存在,会以@PostConstruct、继承InitializingBean类或指定init-method方法的次序依次执行)。
注意:@PostConstruct能起作用,必须在bean配置前启用注解,可以通过配置<context:annotation-config/><context:component-scan base-package="com.imooc.service" />实现。

提问:Spring IOC是如何实现的,如何加载Bean,如何创建单例Bean?

提问:BeanFactory和ApplicationContext之间的关系?

BeanFacotry是spring中比较原始的Factory。如XMLBeanFactory就是一种典型的BeanFactory。原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等。
ApplicationContext接口,它由BeanFactory接口派生而来,因而提供BeanFactory所有的功能。ApplicationContext以一种更向面向框架的方式工作以及对上下文进行分层和实现继承,ApplicationContext包还提供了以下的功能:
• MessageSource, 提供国际化的消息访问
• 资源访问,如URL和文件
• 事件传播
• 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次,比如应用的web层
1.利用MessageSource进行国际化
BeanFactory是不支持国际化功能的,因为BeanFactory没有扩展Spring中MessageResource接口。相反,由于ApplicationContext扩展了MessageResource接口,因而具有消息处理的能力(i18N),具体spring如何使用国际化,以后章节会详细描述。

2.强大的事件机制(Event)
基本上牵涉到事件(Event)方面的设计,就离不开观察者模式。不明白观察者模式的朋友,最好上网了解下。因为,这种模式在java开发中是比较常用的,又是比较重要的。
ApplicationContext的事件机制主要通过ApplicationEvent和ApplicationListener这两个接口来提供的,和java swing中的事件机制一样。即当ApplicationContext中发布一个事件的时,所有扩展了ApplicationListener的Bean都将会接受到这个事件,并进行相应的处理。

Spring提供了部分内置事件,主要有以下几种:
ContextRefreshedEvent :ApplicationContext发送该事件时,表示该容器中所有的Bean都已经被装载完成,此ApplicationContext已就绪可用
ContextStartedEvent:生命周期 beans的启动信号
ContextStoppedEvent: 生命周期 beans的停止信号
ContextClosedEvent:ApplicationContext关闭事件,则context不能刷新和重启,从而所有的singleton bean全部销毁(因为singleton bean是存在容器缓存中的)

虽然,spring提供了许多内置事件,但用户也可根据自己需要来扩展spriong中的事物。注意,要扩展的事件都要实现ApplicationEvent接口。

3.底层资源的访问
ApplicationContext扩展了ResourceLoader(资源加载器)接口,从而可以用来加载多个Resource,而BeanFactory是没有扩展ResourceLoader

4.对Web应用的支持
与BeanFactory通常以编程的方式被创建不同的是,ApplicationContext能以声明的方式创建,如使用ContextLoader。当然你也可以使用ApplicationContext的实现之一来以编程的方式创建ApplicationContext实例 。

ContextLoader有两个实现:ContextLoaderListener和ContextLoaderServlet。它们两个有着同样的功能,除了listener不能在Servlet 2.2兼容的容器中使用。自从Servelt 2.4规范,listener被要求在web应用启动后初始化。很多2.3兼容的容器已经实现了这个特性。使用哪一个取决于你自己,但是如果所有的条件都一样,你大概会更喜欢ContextLoaderListener;关于兼容方面的更多信息可以参照ContextLoaderServlet的JavaDoc。

这个listener需要检查contextConfigLocation参数。如果不存在的话,它将默认使用/WEB-INF/applicationContext.xml。如果它存在,它就会用预先定义的分隔符(逗号,分号和空格)分开分割字符串,并将这些值作为应用上下文将要搜索的位置。ContextLoaderServlet可以用来替换ContextLoaderListener。这个servlet像listener那样使用contextConfigLocation参数。

5.其它区别
1).BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化,这样,我们就不能发现一些存在的Spring的配置问题。而ApplicationContext则相反,它是在容器启动时,一次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误。

2).BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册

提问:BeanFactory和FactoryBean之间的关系?

提问:Spring Bean有哪些扩展点?


OOP

在这里插入图片描述
(1).什么是OOP?

OOP是Object Oriented Programming 面向对象编程 的缩写;

这主要是为了区别于以前的面向过程的程序设计;
OOP指用对象的观点来组织与构建系统,它综合了功能抽象和数据抽象,这样可以减少数据之间的耦合性和代码的出错几率。使用面向对象编程技术可以使得软件开发者按照现实世界里人们思考问题的模式编写代码,可以让软件开发者更好地利用代码直接表达现实中存在的对象,将问题空间直接映射到解空间!类:即class 在面向对象的程序设计中,专门用“类”来表示用户定义的抽象数据类型(user_defined abstract type)。它将具有相同状态、操作和访问机制的多个对象进行了抽象。类具有继承、数据隐藏和多态三种主要特性。利用类的这三种特性可以更好地表示现实世界中事物。类是同一类对象实例的共性的抽象,对象是类的实例化。对象通常作为计算机模拟思维,表示真实世界的抽象,一个对象就像一个软件模块,可以为用户提供一系列的服务—可以改变对象的状态、测试、传递消息等。类定义了对象的实现细节或数据结构。类是静态的,对象是动态的,对象可以看作是运行中的类。类负责产生对象,可以将类当成生产对象的工厂(Object factory).

(2).OOP四(三)大特性

面向对象程序设计的特征:EIPA*
1) 封装 Encapsulation
2) 继承 Inheritance
3) 多态 Polymorphism
4) 抽象 Abstraction
(若问到3项,不包括抽象)

三大特性面试官问的最多的一般是多态

OOP特性 之 封装

封装,就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏;
一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。


OOP特性 之 继承(包括 接口)

继承,指可以让某个类型的对象获得另一个类型的对象的属性的方法;

继承所描述的是**“is-a”**的关系,如果有两个对象A和B,若可以描述为“A是B”,则可以表示A继承B,其中B是被继承者称之为父类或者超类,A是继承者称之为子类或者派生类。

继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。

它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过 “继承”(Inheritance)和“组合”(Composition)来实现。

继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用 基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现(implements)的能力。
——————————
(易错!!!区分“多继承”和“多重继承”)
Java 不支持【多继承】(C语言行为);
但支持【多重继承】,允许一个类实现多个implements接口;

在这里插入图片描述
——————————
extendsimplements有什么不同?

extends
在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。
implements:接口
使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔);
(class c extends a implements c,d....是可以的)

接口是种特殊的抽象类;
是抽象方法定义的集合(全体成员默认用public static final修饰)
接口成员的作用域都是public接口不能被private、protected、static修饰;(常考)

——————————
继承的特点:
1)子类拥有父类的非private属性和方法;
2)子类可以通过两种方式区分和父类的差异(即上述两种),也就是说子类具有一定的扩展性;
3)java只允许单继承,即子类只能继承一个父类;

继承的缺点:
1.父类变,子类就跟着变;因为子类具有与父类相同的类型,所以这个地方有一种牵一发而动全身的感觉;
2.继承和封装是一种悖论,可以说继承破坏了封装,因为继承使得父类的方法和属性对子类是透明的,安全性不高;
3.继承是一种强耦合关系;
——————————
提问:this和super的区别?
this:本质是一个指向本对象的指针,调用本类中另一个构造函数;
super:调用超类中某个构造函数;
this和super都必须写在构造方法的第一行;
this和super不可以同时出现在同一构造函数中;
——————————
面试的话继承一般会问:

  • 什么是继承;
  • 继承的特点;
  • 什么情况下使用继承;
    当需要用到向上转型,即子类到父类的向上转型,可考虑用继承,非这种情况下,慎用继承;

OOP特性 之 多态(包括 重载 overload)

多态是同一个行为具有多个不同表现形式或形态的能力。
多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。

多态性是对象多种表现形式的体现。

现实中,比如我们按下 F1 键这个动作:

如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
如果当前在 Word 下弹出的就是 Word 帮助;
在 Windows 下弹出的就是 Windows 帮助和支持。
同一个事件发生在不同的对象上会产生不同的结果。

多态的优点

  1. 消除类型之间的耦合关系
  2. 可替换性
  3. 可扩充性
  4. 接口性
  5. 灵活性
  6. 简化性

多态存在的三个必要条件

  • 继承
  • 重写 Override
  • 父类引用指向子类对象 向上转型

【多态】的实现基础就是【向上转型】,因为其为传入方法的参数提供了更广阔的自由度

提问:覆盖(重写) Override重载 Overload的区别

方法的重写Override和重载Overload是Java多态性的不同表现。
重载和重写都允许你用相同的名称来实现不同的功能,但是重写是运行时活动,重载是编译时活动。
Override是父类与子类之间多态性的一种表现(所以必须实现继承);
Overload是一个类中多态性的一种表现。

提问:什么时候用重载,什么时候用重写?

对有经验的Java设计师来说,这是一个相当简单的问题。如果你看到一个类的不同实现有着不同的方式来做同一件事,那么就应该用重写(overriding),而重载(overloading)是用不同的输入做同一件事。在Java中,重载的方法签名不同,而重写并不是。
在这里插入图片描述
(overload只在参数上做文章!!!)
(overload只在参数上做文章!!!)
(overload只在参数上做文章!!!)
(overload只在参数上做文章!!!)
(overload只在参数上做文章!!!)

在这里插入图片描述

  • 重写 Override 也称覆盖,它是父类与子类之间多态性的一种表现;
    即父类与子类中有同样的方法名与参数;
    重写式多态,亦称运行时多态,通过“ 动态绑定 ”实现(运行时才知道调用了哪个子类方法);

提问:下列哪个方法与方法public void add(int a) {}为合理的重载方法?
A.public int add(int a)
B.public void add(long a)
C.public void add(int a,int b)
D.public void add(float a)

答:
BCD

提问:Overloaded的方法是否可以改变 返回值的类型 ?

要看具体问什么呢?这个题目很模糊。
如果几个Overloaded的方法的参数列表不一样,它们的返回者类型当然也可以不一样。

但我估计你想问的问题是:如果两个方法的参数列表完全一样,是否可以让它们的返回值不同来实现重载Overload。
这是不行的,
我们可以用反证法来说明这个问题,因为我们有时候调用一个方法时也可以不定义返回结果变量,即不要关心其返回结果,

例如,我们调用map.remove(key)方法时,虽然remove方法有返回值,但是我们通常都不会定义接收返回结果的变量,这时候假设该类中有两个名称和参数列表完全相同的方法,仅仅是返回类型不同,java就无法确定编程者倒底是想调用哪个方法了,因为它无法通过返回结果类型来判断。
————————————————————
注:编译时多态?运行时多态?
方法重载都是编译时多态。根据实际参数的数据类型、个数和次序,Java在编译时能够确定执行重载方法中的哪一个。

class Pa{
    void foo(){
        print("Pa");
    }
}
class Child extends Pa{
    @Override
    void foo(){
        print("Child");
    }
}

@Override作用:在重写一个方法前,方法名前加上此标签,系统会帮你自动检测子类中方法名是否和父类中被重写的方法名相同;
若没有加上这个标签,写错了方法名,子类中的这个方法会被看作一个新方法;

————————

  • 重载 Overload 是一个类中多态性的一种表现。
    即一个类中,同个方法名,但参数不同;
void foo(String str);
void foo(int number);

override从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。overload它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,虚拟机就会根据不同的参数样式,来选择合适的方法执行。

2、override(重写,覆盖)
(1)方法名、参数、返回值相同。
(2)子类方法不能缩小父类方法的访问权限。
(3)子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
(4)存在于父类和子类之间。
(5)方法被定义为final不能被重写。
(6)被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。

3、overload(重载,过载)
(1)参数类型、个数、顺序至少有一个不相同。
(2)不能重载只有返回值不同的方法名。
(3)针对于一个类而言。
(4)不能通过访问权限、返回类型、抛出的异常进行重载;
(5)方法的异常类型和数目不会对重载造成影响。

4、override应用
(1)最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。
(2)除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。

5、总结
override是在不同类之间的行为,overload是在同一个类中的行为。

Overload的方法可以改变返回值的类型,因为它与返回值类型无关

谈谈你对多态的理解?

多态是指:程序中定义的引用变量所指向的具体类型 和 通过该引用变量发出的方法调用 在编
程时并不确定,而是在程序运行期间才确定;即一个引用变量倒底会指向哪个类的实例对象,
该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定;
因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到
各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以
改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。
多态性增强了软件的灵活性和扩展性。

OOP特性 之 抽象

将实体的相关属性和操作根据特定的应用程序进行标识和分组的过程就是抽象。

抽象一般是概念上的同一事物的公共属性或者方法
例如 车 就是一个抽象的对象
小轿车 大货车 是具体的对象 他们都有具备车的公共方法 开动
——————————————
Java 抽象类
在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的;
如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。

由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。
——————————————
提问:抽象类接口的区别?

回答:
接口和抽象类是 Java 面向对象设计的两个基础机制。

抽象类是不能实例化的类,用 abstract 关键字修饰 class,其主要目的代码重用(因为抽象是为了继承,继承是为了重用方法)。
除了不能实例化,形式上和一般的 Java 类并没有太大区别,可以有抽象方法,也可以没有。抽象类大多用于抽取相关 Java 类的共用方法实现或者是共同成员变量,然后通过继承的方式达到代码复用的目的。Java 标准库中,比如collection框架,很多通用部分就被抽取成为抽象类,例如 java.util.AbstractList

接口是对行为的抽象,它是抽象方法的集合,利用接口可以达到 API 定义和实现分离的目的。 接口,不能实例化;
不能包含任何非常量成员(final即常量),任何 field 都是隐含着public static final的意义;
同时,不能有非静态方法实现,也就是说要么是抽象方法,要么是静态方法。Java 标准类库 中,定义了非常多的接口,比如java.util.List

继承 abstract class 使用extends关键词,我们可以参考 Java 标准库中的 ArrayList。
实现 interface 使用implements关键词;

在这里插入图片描述
其中抽象类的“实现”,换句话说:如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。


多态:向上转型 Upcasting

为什么要向上转型?
向上转型就是多态,目的是增加程序的可扩展性

向上转型为什么安全?

只有继承关系才能转换类型;
向上转型体现了Java抽象编程的思想;
多态的实现基础就是向上转型,因为其为传入方法的参数提供了更广阔的自由度;
向上转型:自动转换;向下转型:需要强制转换;
父类中的方法都是接口,可以让子类重写;
在这里插入图片描述
是一种Java的调用方式,是对A的对象的方法的扩充;
即A对象可访问B从A继承来的B复写A的方法;

父类:

public class Pet{
    public void play(){
    }
}

子类:

public class Dog extends Pet{
    public void sitDown(){
    }
}

Pet myBaby = new Dog();
这样是允许的,意思是父类的引用指向子类
在这里插入图片描述
(引用变量就是谁的对象)
在这里插入图片描述

易错:分清楚指向赋值!!!
易错:分清楚指向赋值!!!
易错:分清楚指向赋值!!!
易错:分清楚指向赋值!!!
易错:分清楚指向赋值!!!
易错:分清楚指向赋值!!!
易错:分清楚指向赋值!!!
易错:分清楚指向赋值!!!
——————————————
未使用向上转型时:

class Car {
    public void run() {
        System.out.println("这是父类run()方法");
    }

    public void speed() {
        System.out.println("speed:0");
    }

}

class BMW extends Car {
    public void run() {
        System.out.println("这是BMW的run()方法");
    }

    public void speed() {
        System.out.println("speed:80");
    }
}

public class Benz extends Car {
    public void run() {
        System.out.println("这是Benz的run()方法");

    }

    public void speed() {
        System.out.println("speed:100");
    }

    public void price() {
        System.out.println("Benz:800000$");
    }
    ——————————
    public static void show(Benz benz) {
        benz.run();
        benz.speed();
    }
    public static void show(BMW bmw) {
        bmw.run();
        bmw.speed();
    }
    public static void main(String[] args) {
        show(new Benz()); 
        show(new BMW());
    }

使用向上转型后:

class Car {
    public void run() {
        System.out.println("这是父类run()方法");
    }

    public void speed() {
        System.out.println("speed:0");
    }
}

class BMW extends Car {
    public void run() {
        System.out.println("这是BMW的run()方法");
    }

    public void speed() {
        System.out.println("speed:80");
    }
}

public class Benz extends Car {
    public void run() {
        System.out.println("这是Benz的run()方法");

    }

    public void speed() {
        System.out.println("speed:100");
    }

    public void price() {
        System.out.println("Benz:800000$");
    }
     ——————————
    public static void show(Car car) {//父类实例作为参数
        car.run();
        car.speed();
    }
    public static void main(String[] args) {
        show(new Benz());//向上转型实现
        show(new BMW());
    }
}

提问:下面代码运行结果是?

public class Car{
	public void run(){
	       print("汽车在跑");
	   }
}
public class Benz extends Car{
	public void run(){
	   print("Benz在跑");
	   }
	public static void main(String[] args){
	   Car car = (Car) new Benz();
	   car.run();
	}
}

—————————
答:勿被强制转换误导了,这里有没有强制转换都一样;
这是向上转型,所以结果为Benz在跑;


多态:向下转型(少用)

向上转型虽然使代码变得简洁,体现了JAVA的抽象编程思想,但是也出现了上面提到的子类无法调用其独有的方法,这要怎么解决呢?
所以就有了与之对应的向下转型,弥补了向上转型所带来的缺陷。

Pet myBaby = new Dog(); //myBaby指向的是子类:Dog
myBaby.play();  //父类方法,通过
Dog snoppy = (Dog)myBaby; //父类引用对象指向的是myBaby(上面说到myBaby指向的是Dog,所以这里安全)
snoppy.sitDown();  //子类方法,通过

虽然运行无误,但是要用到强制转换,所以是有风险的;
因为加入Pet下还有Cat类,编译器无法知道你强制转换的到底是谁;

最终要这么写:

public class Master{
    public void palyWithPet(Pet myBaby){
        myBaby.play();
        if(myBaby instanceOf Dog){  //用instanceOf确认父类引用确实指向该子类的对象
            Dog snoppy = (Dog)myBaby;
            snoopy.sitDown();
        }
    }
}

又例如:

Gril是父类,漂亮女孩MMGril是子类

Girl g1=new MMGirl(); //向上转型
MMGirl mmg=(MMGirl)g1;//向下转型,编译和运行皆不会出错

此时mmg指向的实际上还是子类漂亮女孩对象MMGirl,所以这里的向下转型是安全的。因为g1指向的是子类对象。


Girl g2=new Girl();
MMGirl mmg1=(MMGirl)g2; //不安全的向下转型,编译无错但会运行会出错,此时mmg1指向的是由父类对象Girl强制转换成的假MMGirl对象

试想,每个女孩Girl都会笑,但是漂亮女孩MMGirl具有蛊惑男人的微笑,但普通女孩没有;
现在我把一个普通女孩强制转换成了MMGirl,虽然面子上过去了(表现为能编译)但是她不具备勾人心魄的微笑,这就是不安全的体现;

结论

1.在引用数据类型中,只有有继承关系的类型才能进行类型转换;
2.类型转换只是转换看待对象的引用的类型对象本身没有也不可能参与转换
3.父类引用可以自动指向子类对象但只能访问和调用到来自于父类的属性和行为
(只能访问和调用到来自于父类的属性和行为;意思是,调用同名方法时,只能调到子类重写的,无法调用到父类的;同时,无法调用子类独有,而父类不存在的属性和行为)
4. 子类的引用不能指向父类或其它子类对象,就算强转也会导致运行失败并抛出ClassCastException;
5. 把父类引用赋给子类引用,语法上必须使用强制类型转换,要想运行也成功还必须保证父类引用指向的对象一定是该子类对象(最好使用instance判断后,再强转)。


继承和组合

继承树画法:

父类 / 基类 / 超类
       ↑
  子类 / 派生类

箭头代表:子类赋值给父类,子类对象转换成父类,向上转型,父类指向子类;

提问:继承和组合的优缺点:
组合:优点,不破坏封装,彼此相对独立,有较好扩展性;
继承:缺点,破坏封装,父子类紧密依赖,支持扩展,但往往以增加系统结构复杂性作为代价;

组合:优点,支持动态组合,运行时,整体对象可选不同类型的局部对象;
继承:缺点,不支持动态继承,运行时,子类无法选择父类;

组合:优点,整体类可对局部类包装,封锁局部类的接口,提供新的接口;
继承:缺点,子类不能改变父类的接口;

组合:优点,整体类不能自动获取和局部同样的接口;
继承:优点,子类能自动继承父类的接口;

组合:缺点,创建整体类的对象时,需要创建所有局部类的对象;
继承:优点,创建子类;


(3).高内聚低耦合
高内聚低耦合,是软件工程中的概念,是判断设计好坏的标准,主要是面向对象的设计;
主要是看类的内聚性是否高,耦合度是否低。

高内聚:就是说相关度比较高的部分尽可能的集中,不要分散;
低耦合:就是说两个相关的模块尽可以能把依赖的部分降低到最小,不要让两个系统产生强依赖;

例子:

比如订单系统,订单是跟库存息息相关的,没有库存就没有订单,订单强依赖库存;
如果我们把如何扣减库存的逻辑做在订单系统中,那么订单系统和库存系统就耦合了;

同样,订单系统中有扣减库存的逻辑会造成订单系统的功能比较分散,订单系统的功能就不够集中;
所以我们把订单中的库存逻辑给拆分出来一个独立的库存系统,对外暴露扣减库存的接口,订单系统可以通过这个暴露的库存接口来扣减库存;

将订单逻辑与库存逻辑的依赖降低到最小,减掉了订单系统与库存的耦合;
同时订单系统只包含订单处理的逻辑,库存系统只包含了库存的处理逻辑,两个系统的业务上更加内聚;


OOP


1.什么是 Spring Boot?
Spring Boot 是 Spring 开源组织下的子项目,是 Spring 组件一站式处理方案,主要是简化了使用 Spring 的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。

2.为什么要用 Spring Boot?
Spring Boot 优点非常多,如:

独立运行
简化配置
自动配置
无代码生成和XML配置

应用监控

上手容易

问:Spring Boot和SSM本质上的区别?

SSM是什么?是三个臭皮匠(裨将),Spring IoC、Spring MVC、Mybatis的组合。SSM限定死了你只能开发Java Web应用,而且MVC框架必须用Spring MVC,持久层必须用Mybatis,无他!我说的是SSM包含这些啊,没说你不能在这三个基础上自己加其他框架和库上去。

Spring Boot呢?诸葛亮。有了诸葛亮,你用兵的可选方案更多,不管用哪几员将军,出师更顺利。Spring Boot没有和任何MVC框架绑定!没有和任何持久层框架绑定!没有和任何其他业务领域的框架绑定!

你开发Web应用可以用Spring Boot。用spring-boot-starter-web就帮你配置好了Spring MVC。现在我不想用Spring MVC了,换成Spring WebFLux(用spring-boot-starter-webflux)写响应式Web应用可以吗?当然可以,而且这个是Spring 5主推的新Web框架。

你不开发Web应用,只实现纯粹的数据层业务,开发Spring Cloud Stream和Task也可以。

数据持久层,你可以用Spring Data项目下的任何子项目(JPA\JDBC\MongoDB\Redis\LDAP\Cassandra\Couchbase\Noe4J\Hadoop\Elasticsearch…),当然用非Spring官方支持的Mybatis也可以。只要用上对应技术或框架的spring-boot-starter-xxx就可以了。

但是必须要知道,Spring Boot提供的只是这些starters,这些Starter依赖了(maven dependence)对应的框架或技术,但不包含对应的技术或框架本身!

这就是很多人用“全家桶”这个词来比喻Spring Boot的错误之处。肯德基麦当劳的全家桶里面包含了鸡腿、鸡翅、鸡块,这些东西都是包含在里面的。你吃的完是这些,吃不完也是这些。但是Spring Boot不是啊,Spring Boot没有包含Spring MVC,没有包含Mybatis,只有他们对应的starters。

一个更恰当的比喻是,Spring MVC、Spring Data、Websocket这东西对应电脑硬件的显卡、声卡、硬盘、网卡。Spring Boot提供的Starters对应这些硬件的驱动。只要你在主板上插上了这些硬件,Spring Boot提供的对应驱动就能让能让你享受到即插即用(Plug & Play)的体验。Spring Boot提供的是驱动,没有包含显卡、声卡这些硬件本身,这些驱动能够让你DIY的电脑顺畅的引导(boot)并运行起来。

很多Java服务器端的常见第三方框架,Spring Boot都能用Convention over Configuration的方式帮你默认配置好。


回答1:Spring Boot 就像一个脚手架一样,能让你快速的搭建项目,他不是替代SSM的;至于返回什么,完全看前端需求和文档规定吧

Spring Boot就像一个脚手架,但绝对不是一个脚手架
什么是脚手架?我们都见过,就是建筑工地盖楼房的时候外面那一层钢管搭建的架子,还有一层绿网,就是方便构建楼房。但是楼房竣工以后,脚手架是要被拆掉的,不会作为物业的一部分交给业主。软件开发中的脚手架也是类似的,帮助快速搭建项目,而脚手架不会作为最终交付成果的一部分。
你用了Spring Boot,那么Spring Boot以及其他starter的jar都会最终进入你打包编译的jar里,作为你成果的一部分。

那么Spring体系当中,有没有真正的脚手架呢?有的,就是http://start.spring.io,它叫做Spring Initializr Bootstrap your application,就是通过页面上的操作,很快帮你生成搭建好一个初始化好的Spring Boot应用。但是Spring Initializr自己不会进入你最后打包的jar,Spring Initializr是Spring Boot应用的一个简单脚手架工具。

怎么又是一个“简单”的脚手架工具了?因为还有Spring Boot Cli啊。Cli是Command Line Interface的缩写,就是命令行工具。Spring Boot Cli通过命令行交互的方式提供了脚手架功能,你可以用它初始化一个Spring Boot项目,也可以用它完成打包jar的工作。

Theinitcommand lets you create a new project by using start.spring.io without leaving the shell
--Spring Boot 文档

例如运行spring init:

$ spring init --dependencies=web,data-jpa my-project
Using service at https://start.spring.io
Project extracted to '/Users/developer/example/my-project'

就完成了在http://start.spring.io中创建项目的工作。

Spring Boot不是替代SSM的,这个是对的。因为答案上面解释过了,Spring Boot没有和任何Web MVC绑定,没有和任何数据持久化绑定。Spring Boot自己根本无法完成SSM能完成的工作,需要其他starter作为桥梁,自动帮你配置好对应的框架才行。


回答2:springboot采用约定大于配置的方式,简化了大量的xml配置,真正做到了开箱即用?减少了web开发的难度

Spring Boot是采用约定大于配置(就是CoC: Convention over Configuration),简化了大量的XML配置。

约定大于配置 CoC
也称作按约定编程是一种软件设计范式。目的在于减少软件开发人员所需要做出的决定的数量;
从而获得简单的好处,而又不失去其中的灵活性。开发人员仅仅需要规定应用中不符合约定的部分。

这是 maven 最核心的设计理念,很多语言框架都将其思想发扬光大。
遵循约定虽然损失了一定的灵活性,不能随意安排目录结构,不能随意进行函数命名;
但是却能减少配置。更重要的是,遵循约定可以帮助开发人员遵守构建标准。

Spring Boot采用约定优于配置的方式,大量的减少了配置文件的使用;
Spring-boot-starter-web 包含了 Spring MVC 的相关依赖
(包括Json支持的Jackson和数据校验的Hibernate Validator)和一个内置的Tomcat容器;
这使得在开发阶段可以直接通过 main方法或是 JAR 包独立运行一个 WEB 项目;
而在部署阶段也可以打成 WAR 包放到生产环境运行。

难道在Spring Boot出来以前Spring Framework或者其他Spring体系下的框架就没有采用CoC吗?就没有提倡用Java Annotation来简化配置吗? CoC一直就是Spring所倡导的,只是Spring Boot更进一步发扬光大了

真正做到开箱即用?错误, 那还需要Spring Initializr干嘛?或者还需要手动配置POM干嘛?还是要做一定定制化的。如果论开箱即用(Out of Box),我答案里说的传统公司的流程才是开箱即用。新项目Copy老项目就算开箱了,直接上去改就算开始用了。


回答3:SSM:面相XML编程?SpringBoot:面相注解编程?

Spring Boot出现以前,Spring Framework已经在推荐Java Annotation的配置方式了,在所有的文档里都会同时介绍注解和XML两种配置方式,并且优先介绍注解的方式。


回答4:ssm是自己买家具装修?spring boot是全屋定制!

SSM不是自己买家具,而是住酒店,酒店房间里的东西就这些,没得换。你只能自己带一些小件日用品。SSM这家酒店你不喜欢,那就换SSH那家去。Spring Boot是全屋定制,这个形容不错。而且家具种类齐全,品种多样。你只要下单就可以,包送货、包安装调试。


回答5:没有区别?springboot 只是提供了一套默认配置,用于原型的快速开发。

怎么可能没区别,就不多说了。用于原型快速开发这句话存在严重片面理解。快速开发没问题,但绝对不是只限于开发原型。

Spring Boot文档开章明义就讲了:

Spring Boot makes it easy to create stand-alone, production-grade Spring-based Applications that you can run.

怎么是Production-grade(产品级)呢?

Spring Boot文档第V章,专门讲了这些,指的是Actuator,用来监控和控制Spring Boot应用。包括Loggers,Metrics,Auditing,HTTP Tracing,Process Monitoring等等产品环境下需要的一套机制。

回答6:区别就是配置方式不一样,对于实现业务逻辑来说没有任何区别。

区别不仅仅是配置方式不一样,实现业务逻辑更是大有不同!用SSM开发应用,大多数公司的技术栈还在使用JSP,很少采用前后端分离的。而Spring Boot倡导前后端分离的开发,Spring Boot的应用只向前端提供RESTful API。下面一节会重点说这个。




3.Spring Boot 的核心配置文件有哪几个?它们的区别是什么?
Spring Boot 的核心配置文件是:
application(.yml/.application)bootstrap(.yml/.application) 配置文件。

  • 1.加载顺序

这里主要是说明application和bootstrap的加载顺序。

•bootstrap.yml(bootstrap.properties)先加载
•application.yml(application.properties)后加载

bootstrap.yml 用于应用程序上下文的引导阶段。
bootstrap.yml 由父Spring ApplicationContext加载。

父ApplicationContext 被加载到使用 application.yml 的之前。

  • 2.配置区别

bootstrap.yml 和application.yml 都可以用来配置参数。
bootstrap.yml可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。
application.yml 可以用来定义应用级别的,如果搭配 spring-cloud-config 使用 application.yml 里面定义的文件可以实现动态替换。
使用Spring Cloud Config Server时,应在 bootstrap.yml 中指定:

spring.application.name
spring.cloud.config.server.git.uri
  • 3.一些加密/解密信息

实例:
bootstrap.yml:

spring:
 application:
  name: service-a
 cloud:
  config:
   uri: http://127.0.0.1:8888
   fail-fast: true
   username: user
   password: ${CONFIG_SERVER_PASSWORD:password}
   retry:
    initial-interval: 2000
    max-interval: 10000
    multiplier: 2
    max-attempts: 10

当使用Spring Cloud时,通常从服务器加载“real”配置数据。为了获取URL(和其他连接配置,如密码等),您需要一个较早的或“bootstrap”配置。因此,您将配置服务器属性放在bootstrap.yml中,该属性用于加载实际配置数据(通常覆盖application.yml [如果存在]中的内容)。

当然,在一些情况上不用那么区分这两个文件,你只需要使用application文件即可,把全部选项都写在这里,效果基本是一致的,在不考虑上面的加载顺序覆盖的问题上。
————————————
application 配置文件这个容易了解,主要用于 Spring Boot 项目的自动化配置
bootstrap 配置文件有以下几个应用场景:
使用 Spring Cloud Config 配置中心时,这时需要在 bootstrap 配置文件中增加连接到配置中心的配置属性来加载外部配置中心的配置信息;
少量固定的不能被覆盖的属性;
少量加密/解密的场景;


4.Spring Boot 的配置文件有哪几种格式?它们有什么区别?
.properties.yml,它们的区别主要是书写格式不同。
另外,.yml格式不支持@PropertySource注解导入配置。


5.Spring Boot 的核心注解是哪个?它主要由哪几个注解组成的?
启动类上面的注解是@SpringBootApplication,它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:

@SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能。

@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })

@ComponentScan:Spring组件扫描。


6.开启 Spring Boot 特性有哪几种方式?
1)继承spring-boot-starter-parent项目
2)导入spring-boot-dependencies项目依赖


7.Spring Boot 需要独立的容器运行吗?
可以不需要,内置了 Tomcat/ Jetty 等容器。


8.运行 Spring Boot 有哪几种方式?
1)打包用命令或者者放到容器中运行
2)用 Maven/ Gradle 插件运行
3)直接执行 main 方法运行


9.Spring Boot 自动配置原理是什么?
注解 @EnableAutoConfiguration, @Configuration, @ConditionalOnClass 就是自动配置的核心,首先它得是一个配置文件,其次根据类路径下能否有这个类去自动配置。


10.Spring Boot 的目录结构是怎么的?
这个目录结构是主流及推荐的做法,而在主入口类上加上 @SpringBootApplication 注解来开启 Spring Boot 的各项能力,如自动配置、组件扫描等。


11.你如何了解 Spring Boot 中的 Starters?
Starters可以了解为启动器,它包含了一系列可以集成到应用里面的依赖包,你可以一站式集成 Spring 及其余技术,而不需要四处找示例代码和依赖包。如你想使用 Spring JPA 访问数据库,只需加入spring-boot-starter-data-jpa启动器依赖就能使用了。

Starters包含了许多项目中需要用到的依赖,它们能快速持续的运行,都是一系列得到支持的管理传递性依赖。


12.如何在 Spring Boot 启动的时候运行少量特定的代码?
可以实现接口 ApplicationRunner或者CommandLineRunner,这两个接口实现方式一样,它们都只提供了一个run方法,


13.Spring Boot 有哪几种读取配置的方式?
Spring Boot 可以通过@PropertySource,@Value,@Environment,@ConfigurationProperties来绑定变量,


14.Spring Boot 支持哪些日志框架?推荐和默认的日志框架是哪个?
Spring Boot 支持 Java Util Logging,Log4j2, Lockback作为日志框架,假如你使用 Starters 启动器,Spring Boot 将使用 Logback 作为默认日志框架,


15.SpringBoot 实现热部署有哪几种方式?
主要有两种方式:
Spring Loaded
Spring-boot-devtools


16.你如何了解 Spring Boot 配置加载顺序?
在 Spring Boot 里面,可以使用以下几种方式来加载配置。

1)properties文件;
2)YAML文件;
3)系统环境变量;
4)命令行参数;

等等……


17.Spring Boot 如何定义多套不同环境配置?
提供多套配置文件,如:

application.properties
application-dev.properties
application-test.properties
application-prod.properties

运行时指定具体的配置文件


18.Spring Boot 可以兼容老 Spring 项目吗,如何做?
可以兼容,使用@ImportResource注解导入老 Spring 项目配置文件。


19.保护 Spring Boot 应用有哪些方法?
在生产中使用HTTPS;
使用Snyk检查你的依赖关系;
更新到最新版本;
启用CSRF保护;
使用内容安全策略防止XSS攻击;


20.Spring Boot 2.X 有什么新特性?与 1.X 有什么区别?
配置变更
JDK 版本更新
第三方类库更新
响应式 Spring 编程支持
HTTP/2 支持
配置属性绑定
更多改进与增强…


枚举 Enum

Java1.5增加了两个引用:
enum 枚举
annotation 注解

枚举:一组固定的常量组合而成合法值的类型;
建议用enum取代int常量;
枚举天生就是不可变的,因此所有域都应该为final的;他们可以使公有的,但最好做成私有的,并提供访问方法;
——————————————
写一个ENUM方法:

 public enum ProductStatusEnum{

        ON_SALE(1,"ON_SALE"),       //注意写逗号!
        OFF_SALE(2,"OFF_SALE"),     //注意写逗号!
        DELETED(3,"DELETED");       //分号
        
        private final int code;     //枚举天生就是不可变的,因此所有域都应该为final的;
        private final String value;
        
        ProductStatusEnum(int code,String value){    //构造器
            this.code = code;
            this.value = value;
        }
        
        public int getCode() {      //getter
            return code;
        }

        public String getValue() {
            return value;
        }
    }

Int枚举类型:不推荐使用
因为它采用编译时常量,行为不确定,十分脆弱;

public class Const {
    public static final int APPLE_A = 1;    //这里都是引号结尾
    public static final int APPLE_B = 2;    //这里都是引号结尾
    public static final int APPLE_C = 3;    //这里都是引号结尾
}

String枚举类型:不推荐使用

public class Const {
    public static final String CURRENT_USER = "currentUser";    //这里都是引号结尾
    public static final String EMAIL = "emial";                 //这里都是引号结尾
    public static final String USERNAME = "username";           //这里都是引号结尾
}

Scanner

java.util.Scanner 是 Java5 的新特征,我们可以通过 Scanner 类来获取用户的输入;
Scanner A = new Scanner(System.in);
int result = A.nextInt();String result = A.next();

import java.util.Scanner; 
 
public class ScannerDemo {
    public static void main(String[] args) {
        Scanner A = new Scanner(System.in);
        // 从键盘接收数据
 
        // next方式接收字符串
        System.out.println("next方式接收:");
        // 判断是否还有输入
        if (A.hasNext()) {
            String str1 = scan.next();
            System.out.println("输入的数据为:" + str1);
        }
        scan.close();
    }
}

hasNext()Next()效果其实是一样的,系统都会等待输入下一个字符,只是返回值不同;
hasNext()会返回truenext()返回输入的字符。

不确定之处:
若语句中先写输出语句“请输入语句”,然后再是next();运行后:
hasNext()会先要求输入,再返回语句“请输入语句”;
Next()会先返回语句“请输入语句”,再要求输入;

Scanner in = new Scanner(System.in);
int M = in.nextInt();
——————————
提问:用输入/输出写一个程序,让用户输入一些姓名和电话号码,每一个姓名和电话号码经加在文件中。用户通过输入“done”来告诉系统整个列表输入完毕。如果用户输入完整的一个列表,程序将创建一个输出文件并显示或打印出来。

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

public class Input {
    public static void main(String [] args){
        String name;
        String phone;
        Scanner scanner = new Scanner(System.in);
        BufferedOutputStream buff = null;
        try {
            buff = new BufferedOutputStream(new FileOutputStream(new File("phone.txt")));
            while (true){
                System.out.println("请输入姓名,或输入done退出");
                name = scanner.nextLine();
                if (name.trim().equalsIgnoreCase("done")) {
                    break;
                }
                System.out.println("请输入手机号,或者输入done退出");
                phone = scanner.nextLine();
                if (phone.trim().equalsIgnoreCase("done")) {
                    break;
                }
                buff.write((phone + "," + name + "\n").getBytes());
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (buff != null){
                try {
                    buff.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}


Servlet

提问:简述Servlet生命周期?
在这里插入图片描述

  • 1.实例化
    当Servlet容器启动或客户端发送一个请求时,Servlet容器会查找内存中是否存在该Servlet实例,若存在,则直接读取该实例响应请求;如果不存在,就创建一个Servlet实例。
  • 2.初始化 init()
    实例化后,Servlet容器将调用Servlet的init()方法进行初始化(一些准备工作或资源预加载工作);初始化后,Servlet处于能响应请求的就绪状态。
  • 3.服务 service() - doXX()
    当接收到客户端请求时,调用service()的方法处理客户端请求,HttpServletservice()方法会根据不同的请求 转调不同的doXxx()方法。
  • 4.销毁 destroy()
    当Servlet容器关闭时,Servlet实例也随时销毁。其间,Servlet容器会调用Servlet 的destroy()方法去判断该Servlet是否应当被释放(或回收资源)。







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值