SpringBoot
注解
注解 | 解释 |
---|---|
@RestController | 组合注解,等同于spring中的@Controller和@ResponseBody |
@GetMapping | 等同于@RequestMapping(RequestMethod.Get)的简写 |
@SpringBootApplication | 核心注解,标记类为主程序启动类,等同于@SpringBootConfiguration ,@EnableAutoConfiguration 和 @ComponentScan 三个配置 |
@SpringBootConfiguration | 表示Spring Boot配置类 |
@EnableAutoConfiguration | 表示开启自动配置功能 |
@ComponentScan | 组件包扫描器 |
@RunWith(SpringRunner.class) | 测试运行器,加载SpringBoot注解, 用于加载@SpringBootTest |
@SpringBootTest | 标记单元测试类,加载项目上下文环境ApplicationContent |
@ConfigurationProperties | 将配置文件的属性值批量注入 |
@Component | 标注在类上,将类作为bean注入到Spring中 |
@Value | 读取和注入文件属性值 |
@Validated | 引入Spring的数据效验规则 |
进行邮箱规则效验 | |
@ImportResource | 标注在类上,通常放在应用启动类,需指定XML配置文件的路径和名称.—用于加载XML配置文件 |
@Configuration | 指定配置类 |
@Bean | @Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里。添加的bean的id为方法名. |
@Profile | 进行多环境配置,主要作用于类,通过Value属性指定配置环境.(需在全局配置文件中激活) |
@Mapper | 标注在类上,表明该类为Mapper类,将类作为bean注入到Spring中 |
@MapperScan | 扫描注解Mapper类,需指定扫描的包名 |
Spring Data JPA | |
@Entity | 标注数据表映射的实体类,标注在类上,name属性指定数据表名 |
@Id | 标注在类属性或getter方法上,表示对应的主键 |
@GeneratedValue | 与@Id标注在同一位置,可省 |
@Column | 当类属性与表字段名不同时,name属性标注指定 |
依赖启动器
系统自动生成pom.xml
<!--web依赖启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--测试类依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<build>
<!--Maven打包插件-->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
其他
<!--热部署依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>test</scope>
</dependency>
<!--配置处理依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
application.yaml属性注入
Pet实体类
public class Pet {
private String type;
private int age;
//setter方法
}
User实体类
@Component
@ConfigurationProperties(prefix = "user")
public class User {
private int id;
private String username;
private String password;
private List hobby;
private String[] song;
private Map map;
private Pet pet;
//setter方法
}
application.yaml
冒号后有空格!
user:
id: 2
username: linda
password: 123
hobby: [footboll,basketboll]
song: [she,where]
map: {k1: v1,k2: v2}
pet: {type: cat,age: 12}
测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class Tests01 {
@Autowired
private User user;
@Test
public void test01(){
System.out.println(user);
}
}
打印结果
User{id=2, username='linda', password='123', hobby=[footboll, basketboll], song=[she, where], map={k1=v1, k2=v2}, pet=Pet{type='cat', age=12}}
application.properties
application.properties 比 application.yaml 优先级高
user.id=1
user.username=Tom
user.password=123
user.hobby=play,write,look
user.song=love,gone,will
user.map.k1=v1
user.map.k2=v2
user.pet.type=cat
user.pet.age=12
注解对比
对比点 | @ConfigurationProperties | @Value |
---|---|---|
底层框架 | Spring Boot | Spring |
功能 | 批量注入配置文件中的属性 | 单个注入 |
属性setXX()方法 | 需要 | 不需要 |
复杂类型属性注入 | 支持 | 不支持 |
松散绑定 | 支持 | 不支持 |
JSR303数据校验 | 支持 | 不支持 |
SpEL表达式 | 不支持 | 支持 |
Thymeleaf
//依赖启动器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
全局文件配置
spring.thymeleaf.cache=false //页面缓存设置
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.mode=HTML5
spring.thymeleaf.prefix=classpath:/resources/templates/
spring.thymeleaf.suffix= .html
模板
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" media="all"
href="../../css/gtvg.css" th:href="@{/css/gtvg.css}" />
<title>Title</title>
</head>
<body>
<p th:text="#{hello}">欢迎进入Thymeleaf的学习</p>
</body>
</html>
标签表
th:标签 | 说明 |
---|---|
th:insert | 页面片段包含(类似JSP中的include标签) |
th:replace | 页面片段包含(类似JSP中的include标签) |
th:each | 元素遍历(类似JSP中的c:forEach标签) |
th:if | 条件判断,如果为真 |
th:unless | 条件判断,如果为假 |
th:switch | 条件判断,进行选择性匹配 |
th:case | 条件判断,进行选择性匹配 |
th:object | 变量声明 |
th:with | 变量声明 |
th:attr | 通用属性修改 |
th:attrprepend | 通用属性修改,将计算结果追加前缀到现有属性值 |
th:attrappend | 通用属性修改,将计算结果追加后缀到现有属性值 |
th:value | 属性值修改,指定标签属性值 |
th:href | 用于设定链接地址 |
th:src | 用于设定链接地址 |
th:text | 用于指定标签显示的文本内容 |
th:utext | 用于指定标签显示的文本内容,对特殊标签不转义 |
th:fragment | 声明片段 |
th:remove | 移除片段 |
主要语法
说明 | 表达式语法 |
---|---|
变量表达式 | ${…} |
选择变量表达式 | *{…} |
消息表达式 | #{…} |
链接URL表达式 | @{…} |
片段表达式 | ~{…} |
内置对象
#ctx:上下文对象
#vars:上下文变量
#locale:上下文区域设置
#request:(仅限Web Context)HttpServletRequest对象
#response:(仅限Web Context)HttpServletResponse对象
#session:(仅限Web Context)HttpSession对象
#servletContext:(仅限Web Context)ServletContext对象
isPresent()
在java中,为了判断查询的类对象是否存在,采用此方法:
.isPresent()一般与.get()方法合用,当view存在时,view.isPresent()值为true,通过get()方法返回对象。
Thymeleaf
1.相关依赖
<!--thymeleaf依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!--mysql依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
2.导入
<html lang="en" xmlns:th="http://www.thymeleaf.org">
3.href参数传递
th:href="@{/undertakeDemand.action(id=${d.did})}"
4.session对象获取
如session过期,访问该页面会报错,没有username
<li th:object="${session}"><a href="#" th:text="*{USER_SESSION.username}"></a></li>
5.JS传递参数
th:onclick=" 'javascript:undertake('+${d.did}+');' "
<script th:inline="javascript">
function undertake(did) {
location.href = "/undertakeDemand.action?did=" + did;
}
</script>
6.字符拼接
th:text=" '接 单 立 赚 '+${d.reward}+' 元'"
7.页面片段包含
templates/community.html
<head th:replace="section/head :: import">
<meta charset="UTF-8">
<title>Title</title>
</head>
templates/section/head.html
<div th:fragment="import">
<script th:src="@{/js/jquery-3.6.0.js}"></script>
<script th:src="@{/js/bootstrap.js}" type="text/javascript" charset="utf-8"></script>
<link rel="stylesheet" type="text/css" th:href="@{/css/bootstrap.css}" />
<link rel="stylesheet" th:href="@{/css/community.css}">
</div>
结果: !!!!有问题 但是样式能导入。
8.方式一 th:if
<div th:if="${d.state} eq 1">
<button id="undertake" type="button"
class="btn btn-default btn-lg pull-right" th:text=" '已 被 接 单 '+${d.reward}+' 元'">
</button>
</div>
<div th:if="${d.state} ne 1">
<button id="undertake" th:onclick=" 'javascript:undertake('+${d.did}+');' " type="button"
class="btn btn-primary btn-lg pull-right" th:text=" '接 单 立 赚 '+${d.reward}+' 元'">
</button>
</div>
9.方式二 th:swith
<div th:switch="${d.state}">
<button th:case="1" id="undertake" type="button"
class="btn btn-default btn-lg pull-right" th:text=" '已 被 接 单 '+${d.reward}+' 元'">
</button>
<button th:case="*" id="undertake" th:onclick=" 'javascript:undertake('+${d.did}+');' " type="button"
class="btn btn-primary btn-lg pull-right" th:text=" '接 单 立 赚 '+${d.reward}+' 元'">
</button>
</div>
10.疑问—JS传递多个参数(包括文本数据)
th:onclick="'javascript:upUser(\''+${u.id}+'\',\''+${u.username}+'\',\''+${u.password}+'\',\''+${u.userInfo.name}+'\',\''+${u.userInfo.email}+'\',\''+${u.userInfo.tel}+'\',\''+${u.userInfo.address}+'\',\''+${u.userInfo.balance}+'\');'"
在此上下文中只允许返回数字或布尔值的变量表达式,在此表达式的上下文中不信任任何其他数据类型,包括字符串或可以呈现为文本文字的任何其他对象。一个典型的例子是事件处理程序的HTML属性(例如,“onload”),在这种情况下,变量中的文本数据最好输出到“data-*”属性,然后从事件处理程序中读取。
11.把控制器传来的model中的值传递给js变量呢?
@RequestMapping(value = "message", method = RequestMethod.GET)
public String messages(Model model) {
model.addAttribute("message", "hello");
return "index";
}
<script th:inline="javascript">
var message = [[${message}]];
console.log(message);
</script>
12.HTML date-* 属性使用
HTML
onclick=”showDetails(this)” data-type=”bird”
JS
function showDetails(animal)
{
var animalType = animal.getAttribute("data-type");
alert(animalType)
// bird
}
13.Thymeleaf中使用date-* 属性传递文本数据
onclick 与 date- 必须写在统一标签下,否则会找不到数据 ( 不能为大写字母)
<a href="#Model_update"
data-toggle="modal"
th:data-id = "${u.id}"
th:data-username = "${u.username}"
th:data-password = "${u.password}"
th:data-userInfo-name = "${u.userInfo.name}"
th:data-userInfo-email = "${u.userInfo.email}"
th:data-userInfo-tel = "${u.userInfo.tel}"
th:data-userInfo-address = "${u.userInfo.address}"
th:data-userInfo-balance = "${u.userInfo.balance}"
th:onclick="'javascript:upUser(this);'">修改</a>
将接受到的值赋值到id为id_up 的输入框
function upUser(userAndInfo) {
id_up.value = userAndInfo.getAttribute("data-id");
username_up.value = userAndInfo.getAttribute("data-username");
password_up.value = userAndInfo.getAttribute("data-password");
name_up.value = userAndInfo.getAttribute("data-userInfo-name");
email_up.value = userAndInfo.getAttribute("data-userInfo-email");
tel_up.value = userAndInfo.getAttribute("data-userInfo-tel");
address_up.value = userAndInfo.getAttribute("data-userInfo-address");
balance_up.value = userAndInfo.getAttribute("data-userInfo-balance");
}
Java基础
基本类型
数据类型 | 默认值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0f |
double | 0.0d |
char | ‘u0000’ |
String (or any object) | null |
boolean | false |
引用类型
- 在Java中,引用类型的变量非常类似于C/C++的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变了。
- 对象、数组都是引用数据类型。
- 所有引用类型的默认值都是null。
- 一个引用变量可以用来引用任何与之兼容的类型。
- 例子:Site site = new Site(“Runoob”)。
常量
常量在程序运行时是不能被修改的。
在 Java 中使用 final 关键字来修饰常量,声明方式和变量类似:
final double PI = 3.1415927;
转义字符
Java语言支持一些特殊的转义字符序列。
符号 | 字符含义 |
---|---|
\n | 换行 (0x0a) |
\r | 回车 (0x0d) |
\f | 换页符(0x0c) |
\b | 退格 (0x08) |
\0 | 空字符 (0x0) |
\s | 空格 (0x20) |
\t | 制表符 |
“ | 双引号 |
‘ | 单引号 |
\ | 反斜杠 |
\ddd | 八进制字符 (ddd) |
\uxxxx | 16进制Unicode字符 (xxxx) |
自动类型转换
整型、实型(常量)、字符型数据可以混合运算。运算中,不同类型的数据先转化为同一类型,然后进行运算。
转换从低级到高级。
低 ------------------------------------> 高
byte,short,char—> int —> long—> float —> double
数据类型转换必须满足如下规则:
\1. 不能对boolean类型进行类型转换。
\2. 不能把对象类型转换成不相关类的对象。
\3. 在把容量大的类型转换为容量小的类型时必须使用强制类型转换。
\4. 转换过程中可能导致溢出或损失精度,例如:
int i =128;
byte b = (byte)i;
因为 byte 类型是 8 位,最大值为127,所以当 int 强制转换为 byte 类型时,值 128 时候就会导致溢出。
- \5. 浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入,例如:
(int)23.7 == 23;
(int)-45.89f == -45
强制类型转换
\1. 条件是转换的数据类型必须是兼容的。
\2. 格式:(type)value type是要强制类型转换后的数据类型 .
- 1、 整数的默认类型是 int。
- \2. 小数默认是 double 类型浮点型,在定义 float 类型时必须在数字后面跟上 F 或者 f。
变量类型
Java语言支持的变量类型有:
- 类变量:独立于方法之外的变量,用 static 修饰。
- 实例变量:独立于方法之外的变量,不过没有 static 修饰。
- 局部变量:类的方法中的变量。
局部变量
- 局部变量声明在方法、构造方法或者语句块中;
- 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁;
- 访问修饰符不能用于局部变量;
- 局部变量只在声明它的方法、构造方法或者语句块中可见;
- 局部变量是在栈上分配的。
- 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。
实例变量
- 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
- 当一个对象被实例化之后,每个实例变量的值就跟着确定;
- 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;
- 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;
- 实例变量可以声明在使用前或者使用后;
- 访问修饰符可以修饰实例变量;
- 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见;
- 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;
- 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObejectReference.VariableName。
类变量(静态变量)
- 类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法之外。
- 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
- 静态变量除了被声明为常量外很少使用,静态变量是指声明为 public/private,final 和 static 类型的变量。静态变量初始化后不可改变。
- 静态变量储存在静态存储区。经常被声明为常量,很少单独使用 static 声明变量。
- 静态变量在第一次被访问时创建,在程序结束时销毁。
- 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为 public 类型。
- 默认值和实例变量相似。数值型变量默认值是 0,布尔型默认值是 false,引用类型默认值是 null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
- 静态变量可以通过:ClassName.VariableName的方式访问。
- 类变量被声明为 public static final 类型时,类变量名称一般建议使用大写字母。如果静态变量不是 public 和 final 类型,其命名方式与实例变量以及局部变量的命名方式一致。
Java 修饰符
Java语言提供了很多修饰符,主要分为以下两类:
- 访问修饰符
- 非访问修饰符
修饰符用来定义类、方法或者变量,通常放在语句的最前端
访问控制修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
- private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
- public : 对所有类可见。使用对象:类、接口、变量、方法
- protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
我们可以通过以下表来说明访问权限:
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
public |
Y | Y | Y | Y | Y |
protected |
Y | Y | Y | Y/N(说明) | N |
default |
Y | Y | Y | N | N |
private |
Y | N | N | N | N |
默认访问修饰符
使用默认访问修饰符声明的变量和方法,对同一个包内的类是可见的。接口里的变量都隐式声明为 public static final,而接口里的方法默认情况下访问权限为 public。
protected 是最难理解的一种 Java 类成员访问权限修饰词
访问控制和继承
请注意以下方法继承的规则:
- 父类中声明为 public 的方法在子类中也必须为 public。
- 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
- 父类中声明为 private 的方法,不能够被继承。
非访问修饰符
为了实现一些其他的功能,Java 也提供了许多非访问修饰符。
static 修饰符,用来修饰类方法和类变量。
final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
abstract 修饰符,用来创建抽象类和抽象方法。
synchronized 和 volatile 修饰符,主要用于线程的编程。
static 修饰符
静态变量:
static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。静态方法:
static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。
对类变量和方法的访问可以直接使用 classname.variablename 和 classname.methodname 的方式访问。
final 修饰符
final 变量:
final 表示”最后的、最终的”含义,变量一旦赋值后,不能被重新赋值。被 final 修饰的实例变量必须显式指定初始值。
final 修饰符通常和 static 修饰符一起使用来创建类常量。
final 方法
父类中的 final 方法可以被子类继承,但是不能被子类重写。
声明 final 方法的主要目的是防止该方法的内容被修改。
如下所示,使用 final 修饰符声明方法。
final 类
final 类不能被继承,没有类能够继承 final 类的任何特性。
abstract 修饰符
抽象类:
抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。
一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。
抽象类可以包含抽象方法和非抽象方法。
抽象方法
抽象方法是一种没有任何实现的方法,该方法的具体实现由子类提供。
抽象方法不能被声明成 final 和 static。
任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。
如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。
抽象方法的声明以分号结尾,例如:public abstract sample();。
Java 运算符
- 算术运算符
- 关系运算符
- 位运算符
- 逻辑运算符
- 赋值运算符
- 其他运算符
位运算符
Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。
位运算符作用在所有的位上,并且按位运算。假设a = 60,b = 13;它们的二进制格式表示将如下:
A = 0011 1100
B = 0000 1101
-----------------
A&B = 0000 1100
A | B = 0011 1101
A ^ B = 0011 0001
~A= 1100 0011
下表列出了位运算符的基本运算,假设整数变量 A 的值为 60 和变量 B 的值为 13:
操作符 | 描述 | 例子 |
---|---|---|
& | 如果相对应位都是1,则结果为1,否则为0 | (A&B),得到12,即0000 1100 |
| | 如果相对应位都是 0,则结果为 0,否则为 1 | (A | B)得到61,即 0011 1101 |
^ | 如果相对应位值相同,则结果为0,否则为1 | (A ^ B)得到49,即 0011 0001 |
〜 | 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 | (〜A)得到-61,即1100 0011 |
<< | 按位左移运算符。左操作数按位左移右操作数指定的位数。 | A << 2得到240,即 1111 0000 |
>> | 按位右移运算符。左操作数按位右移右操作数指定的位数。 | A >> 2得到15即 1111 |
>>> | 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 | A>>>2得到15即0000 1111 |
Java运算符优先级
类别 | 操作符 | 关联性 |
---|---|---|
后缀 | () [] . (点操作符) | 左到右 |
一元 | expr++ expr— | 从左到右 |
一元 | ++expr —expr + - ~ ! | 从右到左 |
乘性 | * /% | 左到右 |
加性 | + - | 左到右 |
移位 | >> >>> << | 左到右 |
关系 | > >= < <= | 左到右 |
相等 | == != | 左到右 |
按位与 | & | 左到右 |
按位异或 | ^ | 左到右 |
按位或 | | | 左到右 |
逻辑与 | && | 左到右 |
逻辑或 | | | | 左到右 |
条件 | ?: | 从右到左 |
赋值 | = + = - = * = / =%= >> = << =&= ^ = | = | 从右到左 |
逗号 | , | 左到右 |
对应的包装类
包装类 | 基本数据类型 |
---|---|
Boolean | boolean |
Byte | byte |
Short | short |
Integer | int |
Long | long |
Character | char |
Float | float |
Double | double |
连接字符串
String 类提供了连接两个字符串的方法:
string1.concat(string2);
返回 string2 连接 string1 的新字符串。也可以对字符串常量使用 concat() 方法,如:
"我的名字是 ".concat("Runoob");
更常用的是使用’+’操作符来连接字符串,如:
"Hello," + " runoob" + "!"
继承
继承的特性
- 子类拥有父类非 private 的属性、方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
- Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
继承关键字
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。
extends关键字
在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。
implements关键字
使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。
Java 重写(Override)与重载(Overload)
重写(Override)
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。例如: 父类的一个方法申明了一个检查异常 IOException,但是在重写这个方法的时候不能抛出 Exception 异常,因为 Exception 是 IOException 的父类,只能抛出 IOException 的子类异常。
在面向对象原则里,重写意味着可以重写任何现有方法。
方法的重写规则
- 参数列表与被重写方法的参数列表必须完全相同。
- 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
- 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
- 父类的成员方法只能被它的子类重写。
- 声明为 final 的方法不能被重写。
- 声明为 static 的方法不能被重写,但是能够被再次声明。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
- 构造方法不能被重写。
- 如果不能继承一个类,则不能重写该类的方法。
当需要在子类中调用父类的被重写方法时,要使用 super 关键字。
重载(Overload)
重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
最常用的地方就是构造器的重载。
重载规则:
- 被重载的方法必须改变参数列表(参数个数或类型不一样);
- 被重载的方法可以改变返回类型;
- 被重载的方法可以改变访问修饰符;
- 被重载的方法可以声明新的或更广的检查异常;
- 方法能够在同一个类中或者在一个子类中被重载。
- 无法以返回值类型作为重载函数的区分标准。
重写与重载之间的区别
区别点 | 重载方法 | 重写方法 |
---|---|---|
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可以修改 | 一定不能修改 |
异常 | 可以修改 | 可以减少或删除,一定不能抛出新的或者更广的异常 |
访问 | 可以修改 | 一定不能做更严格的限制(可以降低限制) |
Java 多态
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
多态性是对象多种表现形式的体现。
现实中,比如我们按下 F1 键这个动作:
- 如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;
- 如果当前在 Word 下弹出的就是 Word 帮助;
- 在 Windows 下弹出的就是 Windows 帮助和支持。
同一个事件发生在不同的对象上会产生不同的结果。
多态的优点
- \1. 消除类型之间的耦合关系
- \2. 可替换性
- \3. 可扩充性
- \4. 接口性
- \5. 灵活性
- \6. 简化性
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child();
多态的实现方式
方式一:重写:
这个内容已经在上一章节详细讲过,就不再阐述,详细可访问:Java 重写(Override)与重载(Overload)。
方式二:接口
- \1. 生活中的接口最具代表性的就是插座,例如一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,那是因为国外自己定义的接口类型。
- \2. java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。具体可以看 java接口 这一章节的内容。
方式三:抽象类和抽象方法
Java 封装
在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
封装的优点
- \1. 良好的封装能够减少耦合。
- \2. 类内部的结构可以自由修改。
- \3. 可以对成员变量进行更精确的控制。
- \4. 隐藏信息,实现细节。
实现Java封装的步骤
\1. 修改属性的可见性来限制对属性的访问(一般限制为private),例如:
public class Person {
private String name;
private int age;
}
这段代码中,将 name 和 age 属性设置为私有的,只能本类才能访问,其他类都访问不了,如此就对信息进行了隐藏。
\2. 对每个值属性提供对外的公共方法访问,也就是创建一对赋取值方法,用于对私有属性的访问,例如:
public class Person{
private String name;
private int age;
public int getAge(){
return age;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public void setName(String name){
this.name = name;
}
}
this关键字是为了解决实例变量(private String name)和局部变量(setName(String name)中的name变量)之间发生的同名的冲突。
Java Object 类
Java Object 类是所有类的父类,也就是说 Java 的所有类都继承了 Object,子类可以使用 Object 的所有方法。
Object 类位于 java.lang 包中,编译时会自动导入,我们创建一个类时,如果没有明确继承一个父类,那么它就会自动继承 Object,成为 Object 的子类。