分层思想
三层架构概述
三层架构:在软件体系架构中,自上而下将整个业务应用划分为三层:
表示层(Controller):主要是指 与用户交互的界面,用于接收用户输入的数据和显示处理后用户需要的数据。
服务层也叫业务逻辑层(Service): 主要实现业务逻辑。业务逻辑具体包含:验证、计算、业务规则等等,UI层和DAL层之间的桥梁
持久层也叫数据访问层(Repository或DAO层):主要实现对数据的增删改查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。
分层的原因
分层思想的目的即为了高内聚低耦合。
内聚:是从功能角度来度量模块内的联系,一个好的内聚模块应当恰好做一件事,它描述的是模块内的功能联系。
耦合:是软件结构中各模块之间相互连接的一种度量,耦合强弱取决于模块间接口的复杂程度、进入或访问一个模块的点以及通过接口的数据
高内聚低耦合:是软件工程中的概念,是判断软件设计好坏的标准,主要用于程序的面向对象的设计,主要看类的内聚是否高,耦合性是否低。高内聚低耦合目的是使程序模块的可重新用性,移植性大大增强,通常程序结构中各模块的内聚程度越高,模块间的耦合程度就越低。
分包思想(便于管理类文件):
包:本质上是文件夹
创建包:
多级包之间使用“.”进行分割
多级包之的定义规范:公司的网址地址翻转(取掉www)
比如:wedu的官网地址为www.wedu.com
后期定义的包的结构就是:com.wedu.其他包名
包的命名规则:字母都是小写
注意事项:
package语句必须是程序的第一条可执行的代码
package语句在一个Java文件中只能有一个
如果没有package,默认表示无包名
类与类之间的访问:
同一个包下的访问:不需要导包,直接使用即可
不同包下的访问:
(1)、import导包后访问
(2)、通过全类名(包名+类名)访问
注意:import、package、class三个关键字的摆放位置存在顺序关系
package 必须是程序的第一条可执行语的代码
import需写在package下面
class需要在import下面
面向对象编程与面向过程编程比较
面向过程编程:以过程为中心的编程思想,实现功能的每一步都要自己去完成
面向对象编程:以对象为中心的编程思想,指定对象实现具体的功能
类和对象的关系
类的组成
(1)属性:指事物的特征
(2)行为:指事物能执行的操作
类是对事物的一种描述,对象则为具体存在的事物
类的定义
类的组成是由属性和行为构成的
属性:在类中通过成员变量来体现(类中方法体的外面)
行为:在类中通过成员方法来体现(包含参数中定义的变量)
成员变量和局部变量的区别
类中的位置不同:成员变量(类中方法外) 局部变量(类中方法内)
内存中位置不同:成员变量(堆内存) 局部变量(栈内存)
生命周期不同:成员变量(随着对象的存在而存在,随着对象的消失而消失) 局部变量(随着方法的调用而存在,随着方法的调用完毕而消失)
初始化值不同:成员变量(有默认初始化值) 局部变量(没有默认初始化值,必须先定义,赋值才能使用)
构造方法
格式:
public class 类名{
//无参构造方法
修饰符 类名(参数){
}
//有参构造方法
修饰符 类名(数据类型 变量名1,数据类型 变量名2){
//通过调用this来对局部变量赋值(this用来区分局部变量与成员变量重名问题)
this.变量名1 = 数据;
this.变量名2 = 数据;
}
}
格式注意:
修饰符一般用public
方法名与类名相同,大小写也要一致
没有返回值类型,连void都没有
没有具体的返回值(不能用return带回结果数据)
注意事项:
如果没有定义任何构造方法,系统会提供一个默认的无参构造方法。
如果定义了构造方法,系统将不再提供默认构造方法。
标准类的代码编写与使用
成员变量:使用private修饰
构造方法:提供一个无参构造方法;提供一个多个参数的构造方法
成员方法:提供每一个成员变量对应的setXXX和getXxx方法;提供一个展示对象成员变量信息的show()方法
创建对象初始化:无参构造方法创建对象后是使用setXxx方法初始化;带参构造方法创建对象同时完成初始化赋值。
代码块
在java中,使用{}括起来的代码被称为代码块
代码块分类
局部代码块
位置:方法中定义
作用:限定变量的生命周期,及早释放,提高内存利用率
构造代码块
位置:类中方法外定义
特点:每次构造方法执行的时候,都会执行该代码,并且在构造方法执行前执行
作用:将多个构造方法中的相同的代码,抽取到构造代码块中,提高代码复用性
静态代码块
位置:类中方法外定义
特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
作用:在类加载的时候做一些数据初始化操作
关键字
static关键字
概述
static关键字是静态的意思,是java中的一个修饰符,可以修饰成员方法、成员变量
static修饰的成员变量,称为静态变量
static修饰的成员方法,称为成员方法
static修饰的特点
被类的所有对象共享,是我们判断是否使用静态关键字的条件
随着类的加载而加载,优于对象存在,对象需要类被加载后,才能创建
可以通过类名调用,也可以通过对象名调用
注意事项
1、静态方法只能访问静态的成员,不能访问非静态的成员
解释
static修饰的成员在类加载时就加载了,而类加载在创建对象之前执行
非静态成员必须在创建对象以后才能使用
2、非静态方法可以访问静态成员,也可以访问非静态成员
3、静态方法中是没有this关键字
this:代表当前对象的引用
private关键字
概述:private是一个权限修饰符,可以用来修饰成员(成员变量,成员方法)
特点:被private修饰的成员,只能在本类中进行访问,这样可以保护成员不被别的类访问,针对private修饰的成员变量,如果需要被其他类使用,需要提供相应的操作。
提供”get变量名()“方法,用于获取成员变量的值,方法用public修饰。
提供”set变量名(参数)“方法,用于设置成员变量的值,方法用public修饰。
this关键字
概述:this修饰的变量用于指代成员变量,其主要作用是(区分局部变量与成员变量重名问题)
方法的形参如果与成员变量同名,不带this修饰的变量是形参,而不是成员变量
方法的形参没有与成员变量同名,不带this修饰的变量指的是成员变量
final使用
final关键字的作用
-
final代表最终的意思,可以修饰成员变量,成员方法,类
final修饰类、方法、变量的效果
-
final修饰类:该类不能被继承(不能有子类,但可以有父类)
-
final修饰方法:该方法不能被重写
-
final修饰变量:表明该变量是一个常量,不能再次赋值
变量是基本数据类型,不能改变的是值
变量是引用数据类型,不能改变的是地址值,但地址里面的内容是可以改变的
super
this&super关键字:
this:代表本类对象的引用
super:代表父类对象引用
this和super的使用分别
成员变量:
this.成员变量 - 访问本类成员变量
super.成员变量-访问父类成员变量
成员方法:
this.成员方法 - 访问本类成员方法
super.成员方法-访问父类成员方法
构造方法:
this(....) - 访问本类构造方法
suoer(....) - 访问父类构造方法
封装思想
封装
封装概述
是面向对象的三大特征之一(封装、继承、多态)
是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界是无法直接操作的
封装的原则
将类的某些信息隐藏在类内部,不允许外部直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问
封装步骤:
成员变量private,
提供对应的getXxx()/setXxx()方法
封装的好处
通过方法来控制成员变量的操作,提高了代码的安全性
把代码用方法进行封装,提高代码的复用性
wedu管理系统
控制循环结束:
整个系统全部退出:System.exit(状态) 0:正常退出
loop标签(指定退出的层)
继承
概念:
继承是面向对象三大特征之一
继承:让类与类之间产生关系(父子关系),可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和和方法。
实现继承的格式
继承通过extends实现
格式:
//calss 子类 extends 父类{}
举例:class Dog extends Animal{}
注意:
构造方法不能被共享
子类继承父类后,只能使用父类中非私有化的成员
好处与弊端
好处:
提高代码的复用性(多个类相同的成员可以放到同一个类中)
提高代码的维护性(如果方法的代码需要修改,修改一处即可)
弊端:
继承时入侵性的
降低了代码的灵活性
解释:继承关系,导致子类必须拥有父类非私有的成员,让子类多了很多的约束
继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性
应用场景:
当类和类之间,存在相同(共性)的内容,产生了is...a的关系,可以考虑使用继承,不能盲目使用继承
is...a的关系:谁是谁的一种
特点:
1、java中类只支持单继承,不支持多继承
2、java中类支持多层继承,多层继承的非私有化成员可以传递(不能在一个类中体现多层关系,一个类只能体现一层)
成员访问特点
变量的访问特点
在子类方法中访问一个变量,采用的是就近原则。
1、子类局部范围找
2、子类成员范围找
3、父类成员范围找
4、如果都没找到就报错(不考虑父亲的父亲.....)
方法的访问特点
在子类方法中访问一个方法,采用的是就近原则。
1、子类局部范围找
2、子类成员范围找
3、父类成员范围找
4、如果都没找到就报错(不考虑父亲的父亲.....)
方法重写
1、概念
子类出现了和父类中一摸一样的方法声明(方法名一样,参数列表也必须一样)
2、方法重写应用场景
当子类需要父类的功能主题子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
3、Override注解
用来检测当前的方法,是否是重写的方法,起到【校验】的作用
注意:方法重载VS方法重写
方法重写:在继承体系中,子类出现了和父类中一摸一样的方法声明(方法名一样,参数列表也必须一样)
方法重载:同一个类中,方法名相同,参数列表不同,跟返回值无关
方法重写注意事项
1、私有方法不能被重写(父类私有成员子类是不能继承的)
2、子类方法访问权限不能更低(public>默认>私有)
3、静态方法不能被重写,如果子类也有相同的方法,并不是重写父类的方法
权限修饰符
修饰符 | 同一个类中 | 同一个包中子类无关类 | 不同包的子类 | 不同包的无关类 |
---|---|---|---|---|
private | √ | |||
默认 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
继承中构造方法的访问特点
注意:子类中所有的构造方法默认都会访问父类中无参的构造方法
子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,原因在于,每一个子类构造方法的第一条语句默认都是:super()
在父类中完成初始化在构造方法中完成。
一个类中定义多个类,只有一个主类(被public修饰,必须与java文件名同名)
注意事项:
如果父类中没有无参构造方法,只有带参构造方法:
1、通过使用super关键字去显示的调用父类的带参构造方法
//主类
public class Test {
public static void main(String[] args) {
Zi zi = new Zi(18);
}
}
//以下都是副类
class Fu{
int age;
public Fu(int age){
this.age = age;
System.out.println("父类无参构造方法");
}
}
class Zi extends Fu{
public Zi(int age){
//super();调用无参构造方法
super(age);
}
}
2、子类通过this去调用本类中的其他构造方法,本类中的其他构造方法再通过super去手动调用父类的带参的构造方法
//主类
public class Test {
public static void main(String[] args) {
Zi zi = new Zi(18);
}
}
//以下都是副类
class Fu{
int age;
public Fu(int age){
this.age = age;
System.out.println("父类无参构造方法");
}
}
class Zi extends Fu{
public Zi(){
//这里不会在默认super();
this(18); //通过this调用本类中的带参构造方法
}
public Zi(int age){
//super();调用无参构造方法
super(age);
}
}
注意:
this(...)、super(...)必须放在构造方法的第一行有效,并且二者不能共存
无论是私有成员还是非私有成员都可以被继承,但是只用非私有成员能够被访问
开闭原则(对扩展开放对修改关闭):尽量在不更改原有代码的前提下以完成需求。
解决:重新创建一个相似类名的类
例如:前面加Other
抽象类
在java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
特点
抽象类和抽象方法必须使用abstract关键字修饰
//抽象类的定义
public abstract class 类名{}
//抽象方法的定义
public abstract void eat();
注意:抽象方法没有方法体,没有{}中方法声明结束后加上;分号
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
抽象类不能实例化
抽象类可以有构造方法,不能创建对象
抽象类的子类
要么重写抽象类中的所有抽象方法
要么是抽象类
子类继承抽象父类,父类有抽象方法和非抽象方法,此时子类必须重写父类中所有的抽象方法,对于父类中的非抽象的方法,可以选择性是否重写
模板设计模式
设计模式
设计模式是一套被反复使用、多数人知晓的,经过分类编目的、代码设计经验的总结
使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。
模板设计模式
把抽象类整体就可以看成一个模板,模板中不能决定的东西定义成抽象方法
让使用模板的类(继承抽象类的类)去重写抽象方法实现需求
模板设计模式的优势
模板已经定义了通用结构,使用者只需要关心自己需要实现的功能即可
接口
概述
当一个类中所有的方法都是抽象方法时,可以将这个类定义为接口
接口比抽象类还要抽象
java中接口存在的两个意义
1、用来定义规范
2、用来做功能的拓展
接口的定义和特点
接口用关键字interface修饰
public interface 接口名{}
接口不能实例化
可以创建接口的实现类对象使用
接口和类之间是实现关系,类实现接口用implements关键字表示
public class implements 接口名{}
注意:在接口的实现关系中,我们可以看成接口是实现类的父类,但是严格意义上来讲接口和实现类不是父子类关系,只是通过extends连接的两个类才是真正意义上的父子类关系
接口的子类(实现类)
要么重写接口中的所有抽象方法
要么子类也是抽象类
注意:对实现类的命名都是通过接口名+Impl
public class test01 {
public static void main(String[] args) {
InterImpl inter = new InterImpl();
inter.method1();
inter.method2();
inter.method3();
}
}
interface Inter{
//jdk8之前接口中只能是抽象方法
void method1();
//前面默认为public abstract
void method2();
void method3();
}
class InterImpl implements Inter{
//实现类中必须重写接口中所有抽象方法
@Override
public void method1() {
System.out.println("InterImpl中的method1");
}
@Override
public void method2() {
System.out.println("InterImpl中的method2");
}
@Override
public void method3() {
System.out.println("InterImpl中的method3");
}
}
abstract class InterImpl1 implements Inter{
//可以选择性重写其中一个方法
//选择method1进行重写
@Override
public void method1() {
System.out.println("InterImpl1中的method1");
}
}
接口的成员特点
成员特点
成员变量
只能是常量
默认修饰符:public static final
static 可以在不创建对象的前提下就可以访问其成员变量
构造方法
没有,因为接口是要是扩展功能的,而没有具体存在
成员方法
只能是抽象方法
默认修饰符:public abstract
接口组成更新
常量
public static final
抽象方法
public abstract
默认方法(java 8)
静态方法(java 8)
私有方法(java 9)
接口中默认方法
格式
public default 返回值类型 方法名(参数列表){}
作用:解决接口升级问题
注意事项:
默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字
public可以省略,default不能省略
如果实现了多个接口,多个接口存在相同的方法声明,子类就必须对该方法进行重写
接口中静态方法
格式:
public static 返回值类型 方法名(参数列表){}
注意事项
静态方法不可以被接口实现类重写
静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
public可以省略,static不能省略
多态
概念
同一对象,在不同时刻表现出来的不同状态
多态的前提:
-
要有继承或实现关系
-
要有方法重写
-
要有父类引用指向子类对象
多态中的成员访问特点
成员变量
编译看父类,运行看父类
成员方法
编译看父类,运行看子类
示例
package com.oop.polymorphic;
public class demo {
public static void main(String[] args) {
//多态创建对象 父类引用指向子类对象
Fu f = new Zi();
//通过创建对象,访问成员变量 编译看父类,运行看父类
System.out.println(f.num);
//通过创建对象,访问成员方法 编译看父类,运行看子类
f.show();
}
}
class Fu{
int num = 100;
public void show(){
System.out.println("Fu类中的show方法");
}
}
class Zi extends Fu{
int num = 200;
@Override
public void show(){
System.out.println("Zi类中的show方法");
}
}
多态的好处与弊端
好处:提高程序的扩展性。
弊端:不能使用子类特有的成员
多态中的转型
向上转型
父类引用指向子类对象就是向上转型
向下转型
格式:子类型 对象名 = (子类型)父类引用;
示例
package com.oop.polymorphic;
public class demo {
public static void main(String[] args) {
//多态创建对象 父类引用指向子类对象
//向上转型
Fu f = new Zi();
//通过创建对象,访问成员变量 编译看父类,运行看父类
System.out.println(f.num);
//通过创建对象,访问成员方法 编译看父类,运行看子类
f.show();
//向下转型
Zi z = (Zi) f;
z.method();
}
}
class Fu{
int num = 100;
public void show(){
System.out.println("Fu类中的show方法");
}
}
class Zi extends Fu{
int num = 200;
@Override
public void show(){
System.out.println("Zi类中的show方法");
}
public void method(){
System.out.println("我是子类特有的方法, method");
}
}
内部类
内部类的基本使用
内部类的概念
在一个类中定义一个类。
内部类的访问特点
内部类可以直接访问外部类的成员,包括私有
外部类要访问内部类的成员,必须创建对象
成员内部类
在类中方法,跟成员变量是一个位置
外部创建成员内部类格式
格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
私有成员内部类
将一个类,设计为内部类的目的,大多数都是不想让外界去访问,所以内部类的定义应该私有化,私有化之后,再提供一个可以让外界调用的方法,方法内创建内部类对象并调用。
示例
package com.oop.polymorphic;
class Outer {
private int num = 100;
public class InnerClass{
public void show(){
System.out.println(num);
System.out.println("内部类中show方法");
}
}
public void method(){
InnerClass i = new InnerClass();
i.show();
}
}
public class InnerDemo {
public static void main(String[] args) {
Outer.InnerClass innerClass = new Outer().new InnerClass();
innerClass.show();
}
}
静态成员内部类
静态成员内部类访问格式:外部类名.内部类名 对象名 = new 外部类型.内部类名();
静态成员内部类中的静态方法:外部类名.内部类名.方法名();
示例
package com.oop.polymorphic;
class Outer1{
static class Inner{
public void show(){
System.out.println("内部类中的show方法");
}
public static void method(){
System.out.println("内部类中的method方法");
}
}
}
public class StaticClassTest {
public static void main(String[] args) {
Outer1.Inner inner = new Outer1.Inner();
inner.show();
Outer1.Inner.method();
}
}
局部内部类
局部内部类是在方法中定义的类
局部内部类访问方式
局部内部类,外界是无法直接使用,需要在方法内创建对象并使用
该类可以直接访问外部类的成员,也可以访问方法内的局部变量
示例
package com.oop.inter.test;
class Outer {
private int num = 100;
public void method() {
int num2 = 200;
class Inner {
public void show() {
System.out.println(num);
System.out.println(num2);
}
}
Inner inner = new Inner();
inner.show();
}
}
public class OuterDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}
匿名内部类
匿名内部类的前提
存在一个类或者接口,这里的类可以是具体类也可以是抽象类
匿名内部类的格式
格式:new 类名(){重写方法} new 接口名(){重写方法}
匿名内部类的本质
本质:是一个继承了该类或者实现了该接口的子类匿名··········对象
匿名内部类直接调用方法
interface Inter{
void method();
}
class Test{
public static void main(String[] args){
new Inter(){
@Override
public void method(){
System.out.println("我是匿名内部类");
}
}.method(); // 直接调用方法
}
}
Lambda表达式
函数式编程思想概述
函数式思想则尽量忽略面向对象的复杂语法:“强调做什么,而不是以什么形式去做”
标准格式:
(形式参数)->{代码块}
形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
->:由英文中的画线和大于符号组成,固定写法。代表指向动作
代码块:是我们具体要做的事情,也就是写的方法体的具体内容
组成Lambda表达式的三要素:
形式参数,箭头,代码块
Lambda表达式的使用前提
有一个接口
接口有且仅有一个抽象方法