由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。
在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。
Java中的代理按照代理类生成实际不同又分为静态代理和动态代理。静态代理类在编译时期就生成,而动态代理类则是在Java运行时动态生成,动态代理又有JDK代理和CGLib代理。
优缺点:
使用场景:
public interface SellTickets { |
public class TrainStation implements SellTickets { |
public class TrainStationProxy implements SellTickets { |
public class Client { |
Java中提供了一个动态代理类Proxy,Proxy并不是上面我们上述所说的代理对象类,而是提供了一个创建代理对象的静态方法(newProxyInstance方法),来获取代理对象。
实例:同样是上面的卖票案例,这次我们使用JDK动态代理模式来实现
抽象主题类(Subject):
public interface SellTickets { |
真实主题类(RealSubject):
public class TrainStation implements SellTickets { |
import java.lang.reflect.InvocationHandler; |
|
注意:在’ProxyFactory’类中,getProxyObject()方法返回的是SellTickets接口,而不是TrainStation类。
这是因为JDK动态代理模式是基于接口的代理,而不是基于类的代理。
所以,代理对象只能实现与目标对象相同的接口,而不能继承目标对象的类。
同时代理类是程序在运行过程中动态的在内存中生成的类。
上述的执行流程:
<dependencies> |
public class TraninStation { |
import net.sf.cglib.proxy.Enhancer; |
public class Client { |
jdk动态代理基于反射实现,cglib基于继承实现,所以cglib动态代理类是目标类的的子类,而jdk动态代理类是目标对象实现的接口的子类。
建造者模式包含以下几个主要角色:
抽象建造者(Builder):规定了实现复杂对象的哪些部分的创建,并不设计具体的部件对象的创建。
具体建造者(Concrete Builder):实现抽象建造者接口,完成复杂产品的各个部件的具体创建方法。在构建过程完成之后,提供产品的实例。
产品(Product):要构建的复杂对象。产品类通常包含多个部分或属性。
指导者(Director):负责调用具体建造者的方法来构建产品,指导者并不了解具体的构建过程,只关心产品的构建顺序和方式
-Bike产品.java
public class Bike{ |
Builder抽象建造者.java
public abstract class Builder{ |
具体建造者1.java
public class MobikeBuider extends Builder { |
具体建造者2.java
public class OfoBuilder extends Builder{ |
指导者(Director).java
private Builder builder; |
总结:
public abstract class Builder { |
分离构建过程和表示,使得构建过程更加灵活,可以构建不同的表示。
可以更好地控制构建过程,隐藏具体构建细节。
代码复用性高,可以在不同的构建过程中重复使用相同的建造者。
如果产品的属性较少,建造者模式可能会导致代码冗余。
增加了系统的类和对象数量。
在Java中,原型模式(Prototype Pattern)是一种创建型设计模式,它允许通过复制现有对象来创建新对象,而不是通过新建类实例的方式。在实现原型模式时,我们通常会使用clone()
方法,而复制对象时就会涉及到浅克隆(Shallow Clone)和深克隆(Deep Clone)的概念。
浅克隆是指当复制一个对象时,对于基本数据类型的成员变量,会直接复制其值;而对于引用类型的成员变量,则只复制其引用地址(也就是内存地址),而不会复制引用所指向的实际对象。因此,在浅克隆中,原始对象和克隆对象中的引用类型成员变量将指向同一个对象。
在Java中,通过实现Cloneable
接口并重写Object
类的clone()
方法来实现浅克隆。Object
类的clone()
方法默认实现就是浅克隆。
示例代码:
class Address { |
深克隆是指复制对象时,不仅复制对象本身,而且递归复制对象所引用的其他对象。因此,深克隆会复制整个对象网络,使得原始对象和克隆对象之间互不影响,它们拥有各自独立的内存空间。
实现深克隆的方式有多种:
clone()
方法,并在其中对引用类型进行递归克隆(需要引用类型也实现Cloneable
接口并重写clone()
方法)。class Address implements Cloneable { |
如果引用类型嵌套层次很深,或者引用类型没有实现Cloneable
接口,则可以通过序列化的方式实现深克隆。需要确保所有涉及的类都是可序列化的(实现Serializable
接口)。
示例代码:
import java.io.*; |
特性 | 浅克隆 | 深克隆 |
---|---|---|
引用类型复制 | 复制内存地址(共享对象) | 递归复制实际对象(完全独立) |
修改影响 | 修改引用类型成员会影响所有副本 | 修改引用类型成员不影响其他副本 |
实现复杂度 | 简单(默认clone() ) |
复杂(需递归处理所有引用类型) |
性能 | 高效(不创建新对象) | 较低(递归创建新对象) |
适用场景 | 引用类型不可变或无需隔离时 | 引用类型需完全隔离时 |
String
的特殊性:String
是引用类型,但其不可变性(Immutable)使得浅克隆中修改String
值会创建新对象,不会影响原对象(行为类似深克隆)。但其他引用类型(如自定义类)仍需谨慎。Serializable
)是另一种深克隆实现,但要求所有涉及的对象都实现Serializable
接口:public static <T> T deepClone(T obj) throws IOException, ClassNotFoundException { |
意图:
确保一个类只有一个实例,并提供一个全局访问点来访问该实例
注意事项
public class Singleton{ |
测试类
public calss Client{ |
public class Singleton{ |
public enum Singleton{ |
测试类
public class Client{ |
public class Singleton{ |
测试类
|
public class Singleton{ |
public class Singleton{ |
public class Singleton{ |
测试类
|
破会啊单例模式:使上面定义的单例类可以创建多个对象,美剧方式除外,有两种方式:序列化和反射。
例子:
public class Singleton implements Serializable{ |
测试类:
public class Client{ |
public class Client{ |
1.序列化与反序列化破坏单例模式的解决方法:
public class Singleton implements Serializable{ |
public class Client{ |
public class Singleton { |
public class Client{ |
在Java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,又假如我们要更换对象,就要将所有new对象的地方都要需改一遍,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只要和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂中更换对象即可,达到了与对象解耦的目的。所以说,工厂模式最大的优点是:减低耦合。
简单工厂模式不是一个正式的设计模式,但它是工厂模式的基础。它使用一个单独的工厂类来创建不同的对象,根据传入的参数决定创建哪种类型的对象。
工厂方法模式定义了一个创建对象的接口,但由子类决定实例化哪个类。工厂方法将对象的创建延迟到子类。
抽象工厂模式提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类。
public interface Shape{ |
public class Restangle implements Shape{ |
Square.java
public class Square implements Shape{ |
public calss ShapeFactory{ |
public class FactoryPatternDemo{ |
结构:
工厂模式主要包含一下几个主要角色:
抽象产品:定义产品的共同接口或抽象类。它可以是具体产品类的父类或接口,规定了该产品对象的共同方法。
具体产品:实现了抽象产品接口,定义了具体产品的特定行为和属性。
抽象工厂:声明了创建产品的抽象方法,可以是接口或者抽象类,它可以有多个方法用于创建不同类型的产品。
具体工厂:实现了抽象工厂接口,定义了创建具体产品的方法,并返回具体产品对象。
抽象工厂:
public interface CoffeeFactory{ |
具体工厂:
public class AmericanCoffeeFactory implements CoffeeFactory{ |
public class LatteCoffeeFactory implements CoffeeFactory{ |
抽象产品:
public abstract class Coffee{ |
具体产品:
public class AmericanCoffee extends Coffee{ |
public class LatteCoffee extends Coffee{ |
中间依赖类:
public class CoffeeStore{ |
Client 测试类
public class Client{ |
工厂方法模式优势:
解耦:客户端与具体产品类解耦,调用者只需要知道对象的名称即可创建对象。
扩展性:添加新产品只需新增具体工厂和产品类
单一职责:每个工厂只负责创建一种产品
开闭原则:对扩展开放,对修改关闭
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。
抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口,而无需指定具体实现类。通过使用抽象工厂模式,可以将客户端与具体产品的创建过程解耦,使得客户端可以通过工厂接口来创建一族产品。
抽象工厂模式通常涉及一族相关的产品,每个具体工厂类负责创建该族中的具体产品。客户端通过使用抽象工厂接口来创建产品对象,而不需要直接使用具体产品的实现类。
结构:
抽象工厂模式的主要角色如下:
抽象工厂:提供了创建产品的接口,它包含了多个创建产品的方法,可以创建多个不同等级的产品。
具体工厂:主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
抽象产品:定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。
优点:
确保同一产品族的对象一起工作。
客户端不需要知道每个对象的具体类,简化了代码。
缺点:
扩展产品族非常困难。增加一个新的产品族需要修改抽象工厂和所有具体工厂的代码。
适用场景:
1.当系统需要创建多个相关或依赖的对象,而不需要指定具体类时。
2.当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、电冰箱、空调等。
3.系统中有多个产品族,而系统只消费其中的一族产品。
4.当一个产品族中的多个对象被设计成一起工作时,需要确保客户端代码不会依赖于具体的产品类。
抽象工厂:
|
具体工厂:
//抽象工厂模式 美式风味的甜品工厂:美式咖啡、抹茶慕斯 |
//意大利风味甜品工厂:创建意大利风味的咖啡和甜品 |
public abstract class Dessert { |
public abstract class Coffee{ |
public class Trimisu extends Dessert{ |
public class MatchMousse extends Dessert{ |
public class AmericanCoffee extends Coffee{ |
public class LatteCoffee extends Coffee{ |
public class Client { |
简单工厂+配置文件接触耦合:
可以通过工厂模式+配置文件的方式可解除工厂对象和产品对象的耦合,在工厂类中加载配置文件的全类名,并创建对象进行存储,客户端如果需要对象,直接进行获取即可。
第一步:定义配置文件
创建一个配置文件,将产品类全限定名保存在文件中,文件名任意,如:bean.properties
<bean.properties>
coffee=com.liuyue.factorymethod.Coffee
dessert=com.liuyue.factorymethod.Dessert
american=com.liuyue.factorymethod.AmericanCoffee
latte=com.liuyue.factorymethod.LatteCoffee
match=com.liuyue.factorymethod.MatchMousse
trimisu=com.liuyue.factorymethod.Trimisu
<bean.properties>
第二部:改进工厂类:
public class DessertFactory {
public static Dessert createDessert(String type){
try {
//加载配置文件
Properties properties=new Properties();
properties.load(new FileInputStream("bean.properties"));
//获取type全限定类名
String className=properties.getProperty(type);
//通过反射创建对象
return (Dessert) Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static Coffee createCoffee(String type){
try {
//加载配置文件
Properties properties=new Properties();
properties.load(new FileInputStream("bean.properties"));
//获取type全限定类名
String className=properties.getProperty(type);
//通过反射创建对象
return (Coffee) Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
//测试类
public class Client {
public static void main(String[] args) {
//创建的是意大利风味甜品工厂对象
ItalyDessertFactory factory=new ItalyDessertFactory();
//再从工厂里面获取所需要的产品
Coffee coffee=factory.createCoffee();
Dessert dessert=factory.createDessert();
System.out.println(coffee.getName());
dessert.show();
//通过简单工厂+配置文件的方式创建对象
Coffee coffee1=DessertFactory.createCoffee("latte");
Dessert dessert1=DessertFactory.createDessert("trimisu");
System.out.println(coffee1.getName());
dessert1.show();
}
}
Vue是一款用于构建用户界面的渐进式的JavaScript框架(基于数据渲染成用户能看到的界面)
使用 ES 模块构建版本
在本文档的其余部分我们使用的主要是 ES 模块语法。现代浏览器大多都已原生支持 ES 模块。因此我们可以像这样通过 CDN 以及原生 ES 模块使用 Vue:
html
<div id="app">{{ message }}</div>
<script type="module">
import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
createApp({
setup() {
const message = ref('Hello Vue!')
return {
message
}
}
}).mount('#app')
</script>
注意我们使用了 <script type="module">,且导入的 CDN URL 指向的是 Vue 的 ES 模块构建版本。
v-for:列表渲染,遍历容器的元素或者对象的属性
<body>
<div id="app">
<table border="3px" style="padding: 0; background-color: pink; width: 100px; height: 40px;">
<tr v-for="(u,index) in users" :key="index">
<!--index是指序号-->
<td>{{index +1}}</td>
<td>{{u.id}}</td>
<td>{{u.name}}</td>
<td>{{u.gender ===1?'男':'女'}}</td>
</tr>
</table>
</div>
<script type="module">
import { createApp } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
createApp({
data() {
return {
users: [
{ "id": 1, "name": "张三", "gender": 1 },
{ "id": 2, "name": "李四", "gender": 2 },
{ "id": 3, "name": "王五", "gender": 1 }
]
}
}
}).mount('#app');
</script>
v-bind: 动态为HTML标签绑定属性值,如设置href css样式等
注意:动态的为标签的属性绑定值,不能使用差值表达式,得使用v-bind指令。且绑定得数据,必须在data中定义。差值表达式不能出现在标签内部
v-if/v-else-if/v-else: 条件性的渲染某元素,判定为true时渲染,否则反之
v-show: 根据条件展示某元素,区别在于切换的是display属性的值
区别:
1.v-if="表达式",基于条件判断,来控制创建或移除元素节点(条件渲染)例如<span v-if="gender==1">男生</span> ,适用的场景`不频繁切换得场景`。
2.v-show="表达式",基于css样式display来控制显示与隐藏,适用的场景`频繁切换显示隐藏得场景`。
v-model: 在表单元素上创建双向数据绑定
<select id="position" name="position" v-model="Searchfrom.job">
注意:v-model指令用于在表单元素上创建双向数据绑定。
1. v-model指令用于在表单元素上创建双向数据绑定。
2. 当表单元素的值发生改变时,绑定的数据也会发生改变。
3. 当绑定的数据发生改变时,表单元素的值也会发生改变。
v-on:为HTML标签绑定事件
<button type="button" v-on:click="search">查询</button>
注意:v-on:事件名="方法名",方法名不能加引号,且方法名必须在methods中定义。
异步更新
。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。maven的作用:
依赖管理、项目构建、统一项目结构(插件执行框架)
创建maven项目
导入maven项目
建议将要导入的maven项目直接复制到项目目录下
建议选择maven项目的pom.xml文件进行导入
依赖配置的方式例如:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
移除依赖
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</exclusion>
</exclusions>
生命周期
每套生命周期包含一些阶段,阶段都是有顺序的,后面的阶段依赖于前面的阶段
clean(clean阶段):移除上一次构生成的文件
default(compile:编译项目源代码、test:使用合适的单元测试框架进行测试如junit、package:将编译后的文件打包,如jar\\waR等、install: 安装项目到本地仓库)
site(site阶段)
值得注意的是:在同一套生命周期中,当运行后面的阶段时,前面的阶段都会运行
执行指定周期的方式:
1.在ideal中,右侧的maven工具栏,选中对应的生命周期,双击运行
2.在ideal中,找到对应的项目,右键点击open in进入磁盘,用cmd命令行执行对应的生命周期的阶段
例如:mvn clean
用法:测试类中的方法的正确性
优点(对于main方法而言):测试代码与应用程序代码分开,便于维护;可以自动生成测试报告;一个测试方法执行失败,不影响其他的测试方法。
前置工作:在pom.xml文件中引入Junit的jar包依赖,然后在相应的项目中的main同级中的test文件中编写junit测试类
由于测试方法运行不报错,不代表业务方法逻辑没问题,所以通过断言可以检测方法运行结果是否和预期一致,从而判断业务方法的正确性。
在测试方法中使用断言的方法:
Assertions.assertXxxx()
就是接口的具体实现类,直接以参数的形式写出来
依赖范围:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> 指定maven的依赖范围,参见的取值有:compile(默认)、test、provided、runtime**
</dependency>
maven常见爆红问题解决:
要是依赖下载不成功就会爆红,在maven本地仓库中生成了xxxx.lastUpdated文件,若是该文件不删除,依赖就不会再下载了
方法:
根据maven依赖的坐标,找到仓库中对于的xxxx.lastUpdated文件,删除,删除之后重新加载项目即可
或者在本地仓库中通过命令行的形式,执行del /s *.lastUpdated 批量删除指定目录下面的xxxx.lastUpdated文件,删除之后重新加载项目即可
注意:要是重新加载依赖,依赖下载之后还是爆红,此时可以关闭IDEA,重新打开IDEA加载项目即可
打开 Settings/Preferences,进入 Plugins。
搜索并安装 Spring Assistant 插件。
重启IDEA后,新建项目时选择 Spring Assistant 标签。
按照提示填写项目信息并选择依赖,完成后即可生成SpringBoot项目。
访问 Spring Initializr 网站,选择语言、依赖等配置后生成项目。下载解压后,用IDEA打开即可。
方法2:手动创建Maven项目
在IDEA中创建一个普通的Maven项目。
修改 pom.xml 文件,添加SpringBoot相关依赖。
配置主类和资源文件,如 application.yml。
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
通过以上方法,即使在社区版中也可以顺利开发SpringBoot项目。
——所以在Web开发中一般使用会话解决上述多次请求间不能共享数据的问题
对于两种不同的请求方式来说请求参数的存放位置是不同的,
GET:请求参数在请求行中,可见安全性不高,没有请求体
POST:请求参数在请求体中,不可见安全性高,POST请求大小是没有限制的
HTTP协议数据获取:
Web服务器(Tomcat)对HTTP协议的请求数据进行解析,并进行封装到HttpServletRequest,所以可以直接调用Controller方法的时候传递给了该方法。
HTTP响应数据:
Web服务器(Tomcat)对HTTP协议的请求数据进行解析,并进行封装到HttpServletRseponse ,所以可以直接调用Controller方法的时候传递给了该方法。
mybatis 属于一种持久层框架,用于简化JDBC的开发。 用于数据访问dao持久层
官网:https://mybatis.net.cn/getting-started.html
数据库连接池:是一个容器,负责分配管理数据库连接(Connection),允许应用程序重复使用一个现有的数据库连接,而不是在重新建立一个。同时释放空闲时间超过最大空闲时间的连接,来避免因为没有释放连接而引起的数据库连接遗漏。
切换数据库连接池(又spring boot默认的Hikari的数据库连接池转换到Druid):,优势:资源复用,提升系统的响应速度,使用接口DataSource
1.在pom.xml配置文件中,加入配置信息
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
2.application.yml配置文件中
spring.datasource.type/url/driver-class-name/username/password
Mybatis中的#号和$号
#{...}:占位符。执行时,会将#{...}替换为?,生成预编译SQL,使用场景为参数值传递,安全性能高:
${...}:拼接符。直接将参数拼接在SQL语句中,存在SQL注入问题,使用场景为表明,字段名动态设置时使用,不安全,性能低
例子:
@Delete("delete from dept where id=#{id}");
@Select("selectn id,name,score from ${tableName} order by ${sortField}")
<head>
标签与<body>
标签中,写在不同的标签中的执行顺序不同内部(写在body里面):
<body>
<!--内部js-->
<script>
<!-- alert:页面弹出警示框-->
alert("你好,js")
</script>
</body>
1.注意事项:
我们将<script>
尽量放在HTML文件的底部附近的原因是浏览器会按照代码在文件中的顺序加载HTML,如果先加载的JavaScript期望修改其下方的HTML,那么它可能由于HTML尚未被加载而失败。
外部(通过src引入外部js文件):
<body>
<!-- 通过src引入外部js文件-->
<script src="./myjs/my.js"></script>
</body>
<script>
标签中间无需写代码,否则会被忽略!外部的JavaScript会使代码更加有序,更易于复用,且没有脚本的混合,HTML也会更加易于读。内联(代码写在标签内部):
<body>
<button onclick="alert('逗你玩玩')">点击我有好运喔</button>
</body>
输出语法:
<body>
<script>
// 1.文档输出内容(在后面Ctrl+/ 生成单行注释):向body内输出内容 1. 注意事项:如果输出的内容写的是标签,也会被解析成网页元素
document.write('我是图图小淘气')
document.write('<h1>面对世界很好奇</h1>')
// 2.alert直接输出 :页面弹出警告对话框
alter('图图真棒')
/*3.控制台打印输出 给程序员调试使用 (开始shift+alt+a生成多行注解)*/
console.log('看一看对与不对')
console.log('客户端又看不到的地方')
</script>
</body>
总之,JavaScript 可以通过不同的方式来输出数据:
使用 window.alert() 弹出警告框。
使用 document.write() 方法将内容写到 HTML 文档中。
使用 innerHTML 写入到 HTML 元素。
如需从 JavaScript 访问某个 HTML 元素,您可以使用 document.getElementById(id) 方法。请使用 “id” 属性来标识 HTML 元素,并 innerHTML 来获取或插入元素内容:
<!DOCTYPE html>
<html>
<body>
<h1>我的第一个 Web 页面</h1>
<p id="demo">我的第一个段落</p>
<script>
document.getElementById("demo").innerHTML = "段落已修改。";
</script>
</body>
</html>
输入语句:
显示一个对话框,对话框中包含一条文字信息,用来提示用户输入信息
prompt('请输入你的姓名:')
含义:变量是计算机存储数据
的容器
,注意:变量不是数据本身,它仅仅是一个用于存储数据的容器,可以理解为一个个用来装东西的子箱子。
声明(var 、let、const):
let age=18 //注意let 不允许多次声明一个变量,但是var可以多次声明同一个变量(不太好)
精辟: var既可以重新声明,也可以重新赋值;let不能重新声明,可以重新赋值;const 既不能重新声明,也不能重新赋值(专一的好家伙,定义常量时必须赋值)。
变量赋值之后如何更新新值:
直接给它一个不同的值更新它的值,例如:
lat age = 18
age = 19
本质:是程序再内存中申请的一块用来存放数据的小空间
变量命名规则与规范:
JavaScript中优先级越高越先被执行,优先级相同时从左向右执行。
数字类型(number):其中包括整型数和浮点数
1.注意事项:
NaN代表一个计算错误。它是一个不正确的或者是一个未被定义的数字操作所得到的结果(NaN是粘性的:任何对NaN的操作都会返回Nan)。
字符串类型(String):
通过单引号(’’)、双引号(””)、或则反引号(``)包裹的数据都叫字符串,单双引号没有本质上的区别。
2.注意事项:
无论是单双引号都必须成对使用
单引号/双引号可以互相嵌套,但是不可以自己嵌套自己。
必要时可以使用转义字符\,输出单引号或双引号
console.log('我是图图"小淘气"')
console.log("我是图图'小淘气'")
console.log('我是图图\'小淘气\'')
字符串的拼接:
let age = 18
//方法一:模板字符串(外面用反引号``,里面用${变量名})
document.write(`我今年${age}岁了`)
//方法二;直接用+号拼接法
document.write('我今年' + age + '岁了')
布尔类型(Boolean):
有两个固定的值,表示为真时(true),表示为假时(false)
未定义类型(undefined):
未定义是比较特殊的类型,只有一个值undefined。(用在只声明变量,不赋值的情况下,变量的默认值为undefined
空类型(null):
JavaScript中的null仅仅是一代表”无”,”空”,”值未知”的特殊值
3.注意事项:
null和undefined区别:
undefined表示`没有赋值`(还有就是如果检测到变量是undefined就说明没有值传过来)
null表示`赋值了,但是内容为空`(官方解释:把null作为尚未创建的对象,说白了就是,有一个变量里面存放的是一个对象呢,但是对象还没有创建好,可以先给个null,后面再来赋值)
console.log(undefined + 1) //结果为NaN
console.log(null + 1) //结果为1,null是赋了值,但是值为空
强制类型转换是指将一个数据类型强制转换为其他的数据类型。一般是指,将其它的数据类型转换成为String、Number、Boolean。
转换为String类型:
有三种方式:toString()、String()、拼串。
toString():
调用被转换数据类型的toString()方法,该方法不会影响到原变量,它会将转换的结果返回,但是要注意的是:null和undefined这两个值没有toString()方法,如果调用他们的方法会报错。
let a =1234
a=a.toString()
console.log(a)
console.log(typeof a)
String():
调用该函数,并将被转换的数据作为参数传递给函数,使用String()函数作强制转换时,对于Number和Boolean实际上就是调用toString()方法,但是对于null和undefined,就不会调用toString()方法,而是会将null和undefined直接转换为:”null”、”undefined”。
let a =1234
a=String(a)
console.log(a)
console.log(typeof a)
为任何数据类型+""
let a=1234
a=a+""
console.log(a)
console.log(typeof a)
Number()函数:
字符串 –> 数字
1.如果是纯数字的字符串,则直接转换为数字
2.如果字符串中有非数字的内容,则转换为NaN
3.如果是字符串是一个空串或者是一个全是空格的字符串,则转换为0
Boolean –>数字
1.true-->1
2.false-->0
null –>数字
null -->0
undefined –>数字
undefined -->NaN
parseInt():
把一个字符串转换为一个整数
parseFloat():
把一个字符串转换为一个浮点数
注意:
如果是对非String类型使用parseInt()或者parseFloat(),它会先将其转换为String然后再操作。
Boolean()函数:
除了0和NaN,其余都是true
- 字符串–>Boolean
除了空串,其余都是true
- null 和 undefined都会转换为false
- 对象也会转换为true
typeof
关键字检测数据类型除了+号外
的算术运算符,比如 - * /等都会把数据转成数字类型+号作为正号解析可以转成数字型
任何数据和字符串 相加结果都是字符串
console.log('one'+1) //one1
console.log(2-'2') //0
console.log(+12) //12
console(+'123') //123 转换成数字型
一元运算符:(自增,自减)
<!-- 前置自增和后置自增的在运算时区别,but再单独使用的时候没有差别 -->
let i =1
console.log(++i + 2) //结果是4
//注意i=2, i先自加1,变为2之后,在和后面的2相加
console.log(i++ + 2) //结果是3
注意此时i=1 ,先和2相加,先运算输出完毕后,i再自加是2
比较运算符:(比较结果为Boolean型,即只会得到true 或 false)
其他的都一样,只有以下特殊的:
==:左右两边值是否相等
===:左右两边值是否类型和值都相等
!==:左右两边是否不全等
//对比:
=:是赋值
==:是判断
===:是全等(开发中判断是否相等,强烈推荐使用===)
注意:
<!-- 不同类型之间比较会发生隐式转换,最终把数据隐式转换成number类型再比较 例如: 2=='2'结果为true -->
<!-- 字符串比较的字符对应的ASCII码:从左往右一次比较,如果第一位一样在比较第二位,以此类推 -->
<!-- NaN不等于任何值,包括它本身(只要涉及到全为false) -->
<!-- 尽量不要比较小数,因为小数有精度问题 -->
逻辑运算符:
&&(一假为假) ||(一真为真) !(取反)
===
的)作用:声明一个需要的函数,可以把具有相同或相似的逻辑代码“包裹起来”,通过函数调用执行,做到精简代码方便复用。function()->是被设计为执行特定任务的代码块
声明:
function 函数名(){
方法体
}
<!-- 调用 -->
函数名()
<!-- 函数的复用代码和循环重复代码用什么不同:
- 循环代码写完立即执行,不能很方便控制执行位置
- 函数随时调用,随时执行,可重复调用
-->
有返回值的函数
在函数体中使用return关键字能将内部的执行结果交给函数外部使用
function getTotalPrice(x,y){
return x+y
}
let sum=getTotalPrice(1,2)
console.log(sum) //结果为3
return 后面代码不会在被执行,会立即结束当前函数,所以return后面的数据不要换行写
return 函数可以没有return,这种情况函数默认返回值为undefined,例如:
function fn(){
}
let re = fn()
console.log(re) //返回结果为undefined
JavaScript中允许在字符串中使用断行语句:
var x =
"Hello World!";
但是,在字符串中直接使用回车换行是会报错的;所以字符串断行需要使用反斜杠(),如下所示:
var x = "Hello \
World!";
Undefined 不是 Null
在 JavaScript 中, null 用于对象, undefined 用于变量,属性和方法。对象只有被定义才有可能为 null,否则为 undefined。
if (typeof myObj !== "undefined" && myObj !== null)
程序块作用域
在每个代码块中 JavaScript 不会创建一个新的作用域,一般各个代码块的作用域都是全局的。以下代码的的变量 i 返回 10,而不是 undefined:
实例
for (var i = 0; i < 10; i++) {
// some code
}
return i;
在JavaScript中this不是固定不变的,它会随着执行环境的改变而改变
在方法中,this表示该方法所属的对象
var person = {
firstName: "John",
lastName : "Doe",
id : 5566,
fullName : function() {
return this.firstName + " " + this.lastName;
}
};
如果单独使用,this表示全局对象
//在浏览器中,window就是该全局对象为`object Window`
var x = this
//严格模式下,如果单独使用,this 也是指向全局(Global)对象。
"use strict";
var x = this;
在函数中,this表示全局对象
//在函数中,函数的所属者默认绑定到this上
function myFunction(){
return this;
}
在函数中,严格模式下,this是undefined
//严格模式下函数是没有绑定到 this 上,这时候 this 是 undefined。
"use strict";
function myFunction() {
return this;
}
在事件中,this表示接受事件的元素
在 HTML 事件句柄中,this 指向了接收事件的 HTML 元素:
<button onclick = "this.style.display='none'">点我后我就消失不见了</button>
类似call() 和 apply() 方法可以将this引用到任何对象,即显示函数绑定
在JavaScript中函数也是对象,对象则有方法,call()、apply()就是函数对象方法。这两个方法异常强大,允许切换函数执行的上下文环境,即切换this绑定的对象。例如:
<p id="demo"></p>
<script>
var person1 = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person2 = {
firstName:"John",
lastName: "Doe",
}
var x = person1.fullName.call(person2); //// 返回 "John Doe"
document.getElementById("demo").innerHTML = x;
</script>
表单验证:HTML表单验证可以通过JavaScript来完成
HTML 表单验证可以通过 JavaScript 来完成。
以下实例代码用于判断表单字段(fname)值是否存在, 如果不存在,就弹出信息,阻止表单提交:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
function validateForm() {
var x = document.forms["myForm"]["fname"].value;
if (x == null || x == "") {
alert("需要输入名字。");
return false;
}
}
</script>
</head>
<body>
<form name="myForm" action="demo_form.php"
onsubmit="return validateForm()" method="post">
名字: <input type="text" name="fname">
<input type="submit" value="提交">
</form>
</body>
</html>
HTML表单自动验证:
HTML表单验证也可以通过浏览器来自动完成,就是设置必填required,判断其值是否为空,为空时候required属性会阻止表单的提交:
<form action="demo_from.php" method="post">
<input type="text" name="fname" required="required">
<input type="submit" value="提交">
</form>
1.E-mail 验证:在数据在送往服务器前对数据通过条件自动检测
下面的函数检查输入的数据是否符合电子邮件地址的基本语法。
意思就是说,输入的数据必须包含 @ 符号和点号(.)。同时,@ 不可以是邮件地址的首字符,并且 @ 之后需有至少一个点号:
function validateForm(){
var x=document.forms["myForm"]["email"].value;
var atpos=x.indexOf("@");
var dotpos=x.lastIndexOf(".");
if (atpos<1 || dotpos<atpos+2 || dotpos+2>=x.length){
alert("不是一个有效的 e-mail 地址");
return false;
}
}
下面是连同 HTML 表单的完整代码:
实例
<form name="myForm" action="demo-form.php" onsubmit="return validateForm();" method="post">
Email: <input type="text" name="email">
<input type="submit" value="提交">
</form>
数据验证
数据验证用于确保用户输入的数据是有效的。典型的数据验证有:
服务端数据验证
是在数据提交到服务器上后再验证。客户端数据验证
是在数据发送到服务器前,在浏览器上完成验证。
使用 setCustomValidity 设置了自定义提示后,validity.customError 就会变成 true,checkValidity 总是会返回 false。如果要重新判断需要取消自定义提示
,方式如下:
setCustomValidity(‘’)
setCustomValidity(null)
setCustomValidity(undefined)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
function myFunction(){
var x =document.getElementById("id1");
x.setCustomValidity(""); //使用前先取消定义,否则下次点击checkValidity总会返回false,若是不取消下次直接默认checkValidity==false
if(x.checkValidity() == false){
x.setCustomValidity("错误");
document.getElementById("demo").innerHTML=x.validationMessage;
}else{
x.setCustomValidity("对啦");
document.getElementById("demo").innerHTML=x.validationMessage;
}
}
</script>
</head>
<body>
<p>输入数字并点击验证按钮:</p>
<input type="number" id="id1" max="300" min="100" required>
<button type="submit" onclick="myFunction()">点我</button>
<p>如果输入数字100-300以外,会提示错误信息。</p>
<p id="demo"></p>
</body>
</html>
该操作指定要计算一个表达式但是不返回值(但是括号内的表达式还是要运行的)。
javascript:void(0):相当于一个死链接,什么都不会发生。
<a href="javascript:void(0)">单击此处什么也不会发生</a>
区别href=”#”与href=”javascript:void(0)”
#包含了一个位置信息,默认的锚是#top 也就是网页的上端。
而javascript:void(0), 仅仅表示一个死链接。
在页面很长的时候会使用 # 来定位页面的具体位置,格式为:# + id。
如果你要定义一个死链接请使用 javascript:void(0) 。
<a href="javascript:void(0);">点我没有反应的!</a>
<a href="#pos">点我定位到指定位置!</a>
<br>
...
<br>
<p id="pos">尾部定位点</p>
exec():
let reg = /while/i
let str = 'while and while'
console.log(reg.exec(str)) //结果为['while',index:0,input:'while and while',groups:undefined]
<!-- 注意:
1. 正则表达式的exec方法会返回一个数组,数组的第一项是匹配到的字符串,第二项是匹配到的字符串的起始位置,第三项是匹配到的字符串的结束位置,第四项是匹配到的字符串的分组。
2. 正则表达式的exec方法会从字符串的开头开始匹配,如果匹配到了就返回匹配到的字符串,否则返回null。
test():
let reg = /while/i
let str = 'while and while'
console.log(reg.test(str)) //结果为true
<!-- 注意:
1. 正则表达式的test方法会返回一个布尔值,true表示匹配到了,false表示没有匹配到。
match():
let reg = /while/i
let str = 'while and while'
console.log(str.match(reg)) //结果为['while',index:0,input:'while and while',groups:undefined]
<!-- 注意:
1. 正则表达式的match方法会返回一个数组,数组的第一项是匹配到的字符串,第二项是匹配到的字符串的起始位置,第三项是匹配到的字符串的结束位置,第四项是匹配到的字符串的分组。
2. 正则表达式的match方法会从字符串的开头开始匹配,如果匹配到了就返回匹配到的字符串,否则返回null。
3. 正则表达式的match方法会返回一个数组,数组的第一项是匹配到的字符串,第二项是匹配到的字符串的起始位置,第三项是匹配到的字符串的结束位置,第四项是匹配到的字符串的分组。
replace():
let reg = /while/i
let str = 'while and while'
console.log(str.replace(reg,'hi')) //结果为hi and while
<!-- 注意:
1. 正则表达式的replace方法会返回一个字符串,字符串的内容是替换后的字符串。
2. 正则表达式的replace方法会从字符串的开头开始匹配,如果匹配到了就替换,否则返回原字符串。
3. 正则表达式的replace方法会返回一个字符串,字符串的内容是替换后的字符串。
split():
let reg = /while/i
let str = 'while and while'
console.log(str.split(reg)) //结果为['', ' and ']
<!-- 注意:
1. 正则表达式的split方法会返回一个数组,数组的内容是分割后的字符串。
2. 正则表达式的split方法会从字符串的开头开始匹配,如果匹配到了就分割,否则返回原字符串。
3. 正则表达式的split方法会返回一个数组,数组的内容是分割后的字符串。
search():
let reg = /while/i
let str = 'while and while'
console.log(str.search(reg)) //结果为0
<!-- 注意:
1. 正则表达式的search方法会返回一个数字,数字的内容是匹配到的字符串的起始位置。
2. 正则表达式的search方法会从字符串的开头开始匹配,如果匹配到了就返回匹配到的字符串的起始位置,否则返回-1。
7.正则表达式常用量词的含义:
量词 | 含义 |
---|---|
* | 出现0次或连续多次,等价于:{0,}。 |
+ | 出现至少一次,等价于:{1,}。 |
? | 出现0次或则1次。例如,”do(es)?” 可以匹配 “do” 或 “does” 。? 等价于 {0,1}。 |
{n} | n 是一个非负整数。匹配确定的 n 次。例如,’o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。 |
{n,} | n 是一个非负整数。至少匹配n 次。例如,’o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。’o{1,}’ 等价于 ‘o+’。’o{0,}’ 则等价于 ‘o*’。 |
{n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,”o{1,3}” 将匹配 “fooooood” 中的前三个 o。’o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。 |
8.正则表达式常用元字符的含义: | |
元字符 | 含义 |
— | — |
. | 匹配除换行符 \n 之外的任何单字符。要匹配包括 ‘\n’ 在内的任何字符,请使用像”(. |
\w | 匹配字母或数字或下划线或汉字 等价于’[A-Za-z0-9_]’。 |
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\s | 匹配任意的空白符 |
\S | 匹配任意不是空白符的字符 |
\d | 匹配数字 |
\D | 匹配任意非数字的字符 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
\n | 换行符 |
\t | 制表符 |
\r | 回车符 |
\f | 换页符 |
\v | 垂直制表符 |
\e | 转义符 |
\0 | 空字符 |
@Override: 定义在java.lang.Override中,此注解只适用于修饰方法,表示一个方法声明打算重写超类中的另外一个方法声明。
@Deprecated:定义在Java.lang.Deprecated中,此注解可以用于修饰方法,属性,类,表示不鼓励程序员使用这样的元素(通常事因为它很危险或者存在更好的选择),但是可以此方法可以运行。
@SuppressWarnings:定义在Java.lang.SuppressWarnings中,用来抑制编译时的警告信息(后面要有参数才能正确使用),例如:
@SuppressWarnings("all");
@SuppressWarnings("unchecked");
@SuppressWarnings("unchecked","deprecation");
作用:负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明。
类型:@Target ,@Retention, @Documented ,@Inherited (这些类型和他们所支持的类在Java。狼。annotation包中可以找到。)
@Target:用于描述注解的使用范围(即被描述的代码可以用在那些地方)
@Retention:表示需要在说明级别保存该注解信息,用于描述注解的生命周期(Runtime>class>source)
@Document:说明该注解将被包含在Javadoc 中
@Inherited:说明子类可以继承父类中的该注解
格式:
@Target(value ={ElementType.METHOD,ElementType.TYPE})
@Retention(value=RetentionPolicy.RUNTIME)
特点:Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制获得此类似动态语言的特性。Java的动态性让在编程的时候更加灵活!
反射:被视为是动态语言的关键,反射机制允许程序在执行期间借助于’Reflection API’获取任何类的内部信息,并直接操作任意对象的内部属性及方法
Class c=Class.forName("java.lang.String")
加载完类之后,在堆内存的方法中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,通过镜子看到类的结构,所以形象的称为:反射
对比:
获取class 对象:首先获取目标对象类的class对象
获取成员信息:通过 class对象,可以获取类的字段、方法、构造器等信息
操作成员:通过反射API可以读取和修改字段的值、调用方法以及创建对象
创建对象的五种方式: new、newInstance、clone、反序列化、反射。
代码:
package com.st.reflection;
public class Test002 {
public static void main(String[] args) throws ClassNotFoundException {
//通过反射获取类的Class对象
Class c1=Class.forName("com.st.reflection.User");
System.out.println(c1);
//查看他们是不是属于同一个类,就可以查看他们的哈希一不一样
Class c2=Class.forName("com.st.reflection.User");
Class c3=Class.forName("com.st.reflection.User");
Class c4=Class.forName("com.st.reflection.User");
//结果是一样的
//一个类在内存中只有一个Class对象,一个类被加载之后,类的整个结构都会被封装在Class对象中
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c4.hashCode());
}
}
//实体类:pojo entity
class User{
private String name;
private int id;
private int age;
public User(){
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
public int getAge() {
return age;
}
public void setName(String name) {
this.name = name;
}
public void setId(int id) {
this.id = id;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
}
若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class clazz =Person.class;
已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
Class clazz=Class.forName("demo01.Student");
已知某个类的实例,调用实例的getClass()方法获取Class对象
Classclazz=person.getClass();
内置基本数据类型可以用类名.TYPE
还可以利用ClassLoader
综合示例:
package com.st.reflection;
//测试Class 类的创建方式有哪些
public class Test003 {
public static void main(String[] args) throws ClassNotFoundException {
Person person=new Student();
System.out.println("这个人是:"+person.name);
//方式一:通过对象获得
Class c1=person.getClass();
System.out.println(c1.hashCode());
//方式二:通过forname获得
Class c2 = Class.forName("com.st.reflection.Student");
System.out.println(c2.hashCode());
//方式三:通过类名。class 获得
Class<Student> c3 = Student.class;
System.out.println(c3.hashCode());
//方式四:基本内置类型的包装类都有一个Type属性
Class c4=Integer.TYPE;
System.out.println(c4.hashCode());
//获取父类类型
Class c5=c1.getSuperclass();
System.out.println(c5);
}
}
class Person{
public String name;
public Person(){
}
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
class Student extends Person{
public Student(){
this.name="学生";
}
}
class Teacher extends Person{
public Teacher() {
this.name="老师";
}
}
设置IP地址:
终端运行nmtui命令
配置网络(图形界面自己会了)。修改后使用systemctl restart NetworkManager
命令重启,使IP更改信息生效。/etc/NetworkManager/system-connections/
目录中。systemctl stop ufw
和systemctl disable ufw
`关闭防火墙功能。/bin:
bin 是 Binaries (二进制文件) 的缩写, 这个目录存放着最经常使用的命令。
/boot:
这里存放的是启动 Linux 时使用的一些核心文件,包括一些连接文件以及镜像文件。
/dev :
dev 是 Device(设备) 的缩写, 该目录下存放的是 Linux 的外部设备,在 Linux 中访问设备的方式和访问文件的方式是相同的。
/etc:
etc 是 Etcetera(等等) 的缩写,这个目录用来存放所有的系统管理所需要的配置文件和子目录。
/home:
用户的主目录,在 Linux 中,每个用户都有一个自己的目录,一般该目录名是以用户的账号命名的,如上图中的 alice、bob 和 eve。
/lib:
lib 是 Library(库) 的缩写这个目录里存放着系统最基本的动态连接共享库,其作用类似于 Windows 里的 DLL 文件。几乎所有的应用程序都需要用到这些共享库。
/media:
linux 系统会自动识别一些设备,例如U盘、光驱等等,当识别后,Linux 会把识别的设备挂载到这个目录下。
/lost+found:
这个目录一般情况下是空的,当系统非法关机后,这里就存放了一些文件。
/mnt:
系统提供该目录是为了让用户临时挂载别的文件系统的,我们可以将光驱挂载在 /mnt/ 上,然后进入该目录就可以查看光驱里的内容了。
/opt:
opt 是 optional(可选) 的缩写,这是给主机额外安装软件所摆放的目录。比如你安装一个ORACLE数据库则就可以放到这个目录下。默认是空的。
/proc:
proc 是 Processes(进程) 的缩写,/proc 是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,这个目录是一个虚拟的目录,它是系统内存的映射,我们可以通过直接访问这个目录来获取系统信息。
这个目录的内容不在硬盘上而是在内存里,我们也可以直接修改里面的某些文件,比如可以通过下面的命令来屏蔽主机的ping命令,使别人无法ping你的机器:
echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
12. /root:
该目录为系统管理员,也称作超级权限者的用户主目录。
/sbin:
s 就是 Super User 的意思,是 Superuser Binaries (超级用户的二进制文件) 的缩写,这里存放的是系统管理员使用的系统管理程序。
/selinux:
这个目录是 Redhat/CentOS 所特有的目录,Selinux 是一个安全机制,类似于 windows 的防火墙,但是这套机制比较复杂,这个目录就是存放selinux相关的文件的。
/srv:
该目录存放一些服务启动之后需要提取的数据。
16./sys:
这是 Linux2.6 内核的一个很大的变化。该目录下安装了 2.6 内核中新出现的一个文件系统 sysfs 。
sysfs 文件系统集成了下面3种文件系统的信息:针对进程信息的 proc 文件系统、针对设备的 devfs 文件系统以及针对伪终端的 devpts 文件系统。
该文件系统是内核设备树的一个直观反映。
当一个内核对象被创建的时候,对应的文件和目录也在内核对象子系统中被创建。
/tmp:
tmp 是 temporary(临时) 的缩写这个目录是用来存放一些临时文件的。
/usr:
usr 是 unix system resources(unix 系统资源) 的缩写,这是一个非常重要的目录,用户的很多应用程序和文件都放在这个目录下,类似于 windows 下的 program files 目录。
/usr/bin:
系统用户使用的应用程序。
/usr/sbin:
超级用户使用的比较高级的管理程序和系统守护程序。
/usr/src:
内核源代码默认的放置目录。
/var:
var 是 variable(变量) 的缩写,这个目录中存放着在不断扩充着的东西,我们习惯将那些经常被修改的目录放在这个目录下。包括各种日志文件。
/run:
是一个临时文件系统,存储系统启动以来的信息。当系统重启时,这个目录下的文件应该被删掉或清除。如果你的系统上有 /var/run 目录,应该让它指向 run。
在 Linux 系统中,有几个目录是比较重要的,平时需要注意不要误删除或者随意更改内部文件。
/etc: 上边也提到了,这个是系统中的配置文件,如果你更改了该目录下的某个文件可能会导致系统不能启动。
/bin, /sbin, /usr/bin, /usr/sbin: 这是系统预设的执行文件的放置目录,比如 ls 就是在 /bin/ls 目录下的。
值得提出的是 /bin、/usr/bin 是给系统用户使用的指令(除 root 外的通用用户),而/sbin, /usr/sbin 则是给 root 使用的指令。
/var: 这是一个非常重要的目录,系统上跑了很多程序,那么每个程序都会有相应的日志产生,而这些日志就被记录到这个目录下,具体在 /var/log 目录下,另外 mail 的预设放置也是在这里。
检查是否安装了gcc
rpm -qa|grep gcc
若是没有显示有安装包,则可以用dnf命令安装所需要的软件包,步骤如下:
mount /dev/cdrom /media