1.1、注解
注解困扰了我很长时间,看了一堆概念。要理解注解,首先得理解两个概念元数据和反射机制
元数据是关于数据的数据。它提供了关于其他数据的信息或描述。例如,在数据库中,记录的结构(字段类型、字段名称等)就算是元数据。
反射机制是一种功能,使得程序能够在运行时获取类的信息(例如类名、方法、属性等),并可以动态调用这些类的方法或访问其属性。
注解可以看作是特殊形式的元数据,常与反射结合使用,允许根据注解的信息动态处理代码逻辑。
如下是标准概念:
Java 注解是一种特殊的语法,用于向代码添加元数据。简单来说,注解就像是给代码加上标签,提供额外的信息。这些信息可以在编译时、运行时或通过工具处理时被利用,但注解本身不会直接影响代码的执行。
1.1.1、@RequestMapping
@RequestMapping
注解用于定义一个可以被 HTTP 请求访问的控制器方法。当 JavaScript 向 /sys/gtVal
发送 POST 请求时,Spring 框架会根据请求的路径和方法将其映射到 login
方法上,并执行该方法。
@RequestMapping(value = "/sys/gtVal", method = RequestMethod.POST)
public V login() {
...
}
该注解还分类级、方法级别
- 类级别的
@RequestMapping
用于定义一个基础路径,所有在该类中的方法都将基于这个路径展开。 - 方法级别的
@RequestMapping
则用于细化具体的路径及请求方式。
@RequestMapping("/miniapp")
public class MiniappSqykzController {
@RequestMapping(value = "/miniList", method = RequestMethod.GET)
public List miniList(@RequestParam("type") String type) {
...
}
}
上面代码,它的完整URL就是/miniapp/miniList
。
1.1.1.1、Post/GetMapping
@PostMapping
与@GetMapping
是@RequestMapping
的特化用法,更简洁易读。@PostMapping
用于处理 HTTP POST 请求,@GetMapping
用于处理 HTTP GET 请求。
1.1.1.2、发起与接收请求
@GetMapping
、@PostMapping及@RequestMapping
一般都是用来接收请求的。- 当与 HTTP 客户端库(如 Feign)配合时,是用来发起请求的。
@FeignClient(value = "service-provider")
public interface ApiProviderFeign {
@PostMapping("/api/service/provider/getUserInfo")// 此处发起请求
Map<String, String> getUserInfo(@RequestParam("username") String username);
}
1.1.2、@Override
@Override
注解是 Java 中的一个标记注解,用于指示一个方法正在重写父类中的方法。它可以帮助编译器检查是否正确地重写了方法,并使代码更具可读性。使用 @Override
注解的优点包括:
-
编译时检查:如果方法名或参数不匹配,编译器会报错,帮助避免潜在的错误。
-
代码可读性:明确表明该方法是重写的,有助于其他开发者理解代码。
-
维护性:在将来的代码更改中,确保方法的重写关系不被意外破坏。
常见用法示例:
class Parent {
void display() {
System.out.println("Display from Parent");
}
}
class Child extends Parent {
@Override
void display() {
System.out.println("Display from Child");
}
}
在上面的例子中,Child
类重写了 Parent
类的 display
方法。在重写时使用 @Override
注解是一个良好的编程习惯。
1.1.3、@FeignClient
@FeignClient
是 Spring Cloud Feign 模块中的一个注解,用于声明一个 Feign 客户端。Feign 是一个声明式的 Web 服务客户端,可以帮助简化 HTTP API 的调用。使用 @FeignClient
注解,开发者能够通过接口定义与其他服务的 RESTful API 的交互,以下是关键点:
-
声明式 HTTP 客户端:通过接口定义 API 方法,Feign 会为这些方法自动生成 HTTP 请求。你只需关注接口的设计,而无需处理底层的 HTTP 细节。
-
简化的配置:可以通过使用注解,如
@GetMapping
、@PostMapping
等,指定 HTTP 方法和路径。Feign 会自动实现这些方法。 -
服务发现:与 Spring Cloud Eureka 集成时,可以在
@FeignClient
中指定服务名,Feign 会根据服务名称动态解析其具体地址。 -
负载均衡:结合 Ribbon 等负载均衡组件,Feign 支持自动负载均衡。
-
集成其他特性:可以与 Spring Cloud 的其他功能(如 Hystrix、熔断器)集成,以增强服务调用的可靠性。
示例:
@FeignClient(name = "user-service")
public interface UserServiceClient {
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long id);
}
在这个例子中,UserServiceClient
接口通过 @FeignClient
注解定义与名为 user-service
的服务的交互,并使用 @GetMapping
指定具体的 API 路径。
-
@FeignClient
注解:用于定义一个 Feign 客户端,以便在服务之间进行 HTTP 调用。Feign 客户端允许你通过接口的形式来调用其他微服务的 RESTful API。 -
name
属性:name
属性指定了 Feign 客户端的名称。在这里,user-service
通常代表另一个微服务的名称,这个名称通常是在服务注册中心(例如 Eureka)中注册的服务ID。通过这个名称,Feign 可以找到并与对应的服务进行通信。
1.1.4、@RequestBody
@RequestBody
是 Spring 框架中用于处理 HTTP 请求体的一个注解。它通常用于将 HTTP 请求的正文内容绑定到控制器方法的参数上。这个注解可以应用在方法的参数上,也可以应用在整个类上,以指示 Spring MVC 如何处理该参数或整个请求体。
以下是 @RequestBody
的一些常见用法和示例:
假设你有一个控制器方法需要从请求体中接收 JSON 数据并将其转换为 Java 对象,你可以使用 @RequestBody
来实现这一点:
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
public class MyController {
@PostMapping("/user")
public User createUser(@RequestBody User user) {
// 处理用户数据
return user;
}
}
在这个示例中,当客户端发送一个包含 JSON 数据的 POST 请求到 /api/user
时,Spring 会自动将 JSON 数据反序列化为 User
对象,并传递给 createUser
方法。
1.1.5、@ResponseBody
@ResponseBody是Spring MVC框架中的一个核心注解,用于指示方法的返回值应该直接写入HTTP响应体中。
在Spring框架中,@ResponseBody注解的使用非常关键,它允许开发者轻松地将方法的返回值直接写入HTTP响应体中。这对于构建RESTful Web服务尤其重要,因为它允许以一种声明式的方式处理JSON、XML等格式的数据。通过使用@ResponseBody注解,开发者可以简化开发过程,专注于业务逻辑的实现,而无需关心数据的序列化和传输细节。
此外,当使用@RestController注解时,所有方法都隐式地具有@ResponseBody效果,但在非@RestController类中需要显式添加此注解。这意味着在@RestController类中,即使没有明确标注@ResponseBody,方法的返回值也会被自动序列化为JSON或XML格式,并写入HTTP响应体中。而在其他类型的控制器类中,则需要在方法上明确标注@ResponseBody以实现相同的效果。
1.1.6、@SysLog
@SysLog("banner列表")
1.2、反射
反射是指java在运行时允许查询、访问和修改类、接口、字段和方法的信息。反射提供了一种动态地操作类的能力,这在很多框架和库中被广泛使用,例如Spring框架的依赖注入。
这个“运行时”是指Java虚拟机(JVM)执行字节码后的阶段,也就是当程序已经被编译成.class文件,并在JVM中运行时。
java代码在计算机中经历的三个阶段
Java中的反射概念允许程序在运行时获取类的信息和操作对象。而在JavaScript中,虽然没有严格意义上的“反射”,但可以通过一些内置对象和方法实现类似的功能。
在JavaScript中,常用的相关概念包括:
typeof
:获取变量的数据类型。instanceof
:检查对象是否是某个构造函数的实例。Object.keys()
、Object.values()
、和Object.entries()
:获取对象的键、值或键值对。Reflect
:ES6引入的Reflect对象,提供了很多与对象操作相关的静态方法,支持一些类似反射的功能。
通过这些特性,JavaScript能够在运行时动态访问和操作对象的属性和方法。JS中感觉正常到都忽略了其存在的用法,在java中竟然被提升到一个专门的语法概念来讲了。
反射优秀博文:JAVA反射机制_java的反射机制-CSDN博客
1.3、HashMap
HashMap就是键值对,与es6中Map类似。
添加元素使用put()
方法,获取元素使用get()
方法,删除元素使用remove()
方法,遍历元素可以使用增强的for循环或迭代器。
1.4、函数
在 Java 中,不同的函数声明有不同的目的和使用场景。
-
public static void main(String[] args)
:- 这是 Java 应用程序的入口点。
main
方法是程序启动时执行的特殊方法。 public
:表示该方法可以被任何其他类访问。static
:意味着该方法属于类本身,而不是类的实例,可以直接通过类名调用。void
:表示该方法不返回任何值。String[] args
:用于接收命令行参数的字符串数组。
- 这是 Java 应用程序的入口点。
-
public R pwdLogin(String[] args)
:- 这是一个普通的实例方法(如果没有
static
关键字)。它执行特定的功能,例如用户登录。 R
是该方法的返回类型,表示该方法将返回一个R
类型的对象。- 方法中包含若干参数,用于接收用户名、密码、动作名称以及 HTTP 请求和响应对象。
- 这是一个普通的实例方法(如果没有
总结:
main
方法是程序的入口点,而其他方法(如pwdLogin
)用于实现特定功能。- 返回类型(如
void
或R
)决定了该方法是否返回结果以及返回的结果类型。 - 参数数量和类型根据方法的需要而变化。
1.5、文件类型
1.5.1、properties文件
在Java编程中,pro.properties文件通常是一个属性文件,用于存储应用程序的配置信息。这种文件格式简单易读,每行包含一个键值对,以等号(=)分隔,如key=value
。属性文件广泛应用于各种场景,如数据库连接配置、系统设置、国际化资源等。
1.6、package
java文件首行中package语句是不是可有可无?该语句只是为了便于阅读代码?
在Java中,package
语句并不是可有可无的。它用于声明一个类所属的包(package)。包是Java中的一种命名空间机制,用于组织类和接口,避免命名冲突。
作用
- 组织代码:通过包可以将相关的类和接口组织在一起,使项目结构更加清晰。
- 命名空间管理:不同包中的类可以有相同的名字,而不会冲突。例如,两个不同的包中都可以有一个名为
MyClass
的类。 - 访问控制:包还可以用于控制类的访问权限。默认情况下,只有同一个包内的类才能互相访问,除非使用特定的访问修饰符(如
public
、protected
)。
总结
- 必须性:
package
语句不是可有可无的,它是Java语言的一部分,用于定义类的包。 - 功能:它不仅有助于代码的组织和管理,还提供了一种有效的命名空间管理方式。
- 可读性:虽然
package
语句本身并不直接影响代码的运行,但它提高了代码的可读性和可维护性。
一个包(package)可以定义为一组相互联系的类型(类、接口、枚举和注释),为这些类型提供访问保护和命名空间管理的功能。
同一个package下的类之间互相调用时,不需要使用import语句。这是因为在同一个包内,所有的类都是可见的,可以直接通过类名进行访问。js中没有包的概念,java的包真好用!
import com.runoob.mypackage.*;
这样,你可以导入 com.runoob.mypackage 包中的所有类,从而在当前源文件中使用该包中的任何类的方法、变量或常量。注意,使用通配符 * 导入整个包时,只会导入包中的类,而不会导入包中的子包
1.7、接口Interface
让我们来看一个例子,这个例子创建了一个叫做animals的包。通常使用小写的字母来命名避免与类、接口名字的冲突。
在 animals 包中加入一个接口(interface):
Animal.java 文件代码:
/* 文件名: Animal.java */
package animals;
interface Animal {
public void eat();
public void travel();
}
接下来,在同一个包中加入该接口的实现:
MammalInt.java 文件代码:
package animals;
/* 文件名 : MammalInt.java */
public class MammalInt implements Animal{
public void eat(){
System.out.println("Mammal eats");
}
public void travel(){
System.out.println("Mammal travels");
}
public int noOfLegs(){
return 0;
}
public static void main(String args[]){
MammalInt m = new MammalInt();
m.eat();
m.travel();
}
}
然后,编译这两个文件,并把他们放在一个叫做animals的子目录中。 就是包和接口的实践了
1.8、数据类型
1.8.1、数组
java中数组的声明方式跟js中有啥区别?
1. 声明方式
Java:
int[] numbers = new int[5]; // 声明一个整型数组,长度为5
String[] names = {"Alice", "Bob", "Charlie"}; // 使用初始化列表
JavaScript:
let numbers = new Array(5); // 声明一个数组,长度为5
let names = ["Alice", "Bob", "Charlie"]; // 使用初始化列表
2. 类型
-
Java:强类型语言,数组必须指定类型,如
int[]
,String[]
等。 -
JavaScript:动态类型语言,数组可以包含多种类型的数据。
3. 长度
-
Java:数组长度在创建时固定,不能动态改变。
-
JavaScript:数组的长度是动态的,可以随时添加或减少元素。
4. 方法和属性
- Java:数组是对象,但更像基本数据结构,没有太多内置方法。
- JavaScript:数组是对象,拥有丰富的内置方法(例如
push()
,pop()
,map()
,filter()
5.返回值
Java中返回空数据不像JS中return [],这么随意。如下
if (whiteArr == null) {
return new String[0];
}else {
return whiteArr;
}
1.8.2、字符串
1.8.2.1、char和String的区别?
Java中String跟JS区别较大,JS中较粗暴String可以是任意长度的,也统一。java则区分较细,如下
字符:char
使用单引号,长度为1的单个字符。操作方法很少
字符串:String
使用双引号,包含多个字符。操作方法较多
1.8.3、数据结构
数组(Array):
int[] array = new int[5];
- 特点: 固定大小,存储相同类型的元素。
- 优点: 随机访问元素效率高。
- 缺点: 大小固定,插入和删除元素相对较慢。
列表(List):
List<String> sites = new ArrayList<String>();
sites.add("Google");
sites.get(0); // 访问第1个元素
- 特点: 动态数组,可变大小。
- 优点: 高效的随机访问和快速尾部插入。
- 缺点: 中间插入和删除相对较慢。
Array与List的区别在于一个固定大小,一个动态数组
映射(Map):
js中的对象,对应java中的map(键值对)
Map<String, Integer> hashMap = new HashMap<>();
Map<String, Integer> treeMap = new TreeMap<>();
hashMap.put("one", "Google");
hashMap.put("two", "Runoob");
hashMap.get('one'); // "Google"
...详情参考:Java 数据结构 | 菜鸟教程
1.9、interface
接口本身并不能被调用,必须通过实现它的类或代理对象来进行调用。