java 基础语法速成

java 基础语法速成

彩笔稍微整理了一下,速成用,小登期末乖乖刷题去。

参考了狂神说java

0. 一些概念

常用快捷键

alt+insert 快速添加getter和setter
Ctrl+D 复制当前行到下一行

第一个程序

当前文件夹上面的路径改成cmd,然后回车开命令行

在命令行输入下面命令

javac hello.java 编译生成class文件

java hello 运行hello.class

//hello.java
//下面类名要跟文件名一致
public class hello{
    //main方法
	public static void main(String[] args){
		System.out.println("Hello World!");
	}
}

标识符和关键字

java所有的组成部分名字,类名,变量名以及方法名。

48个关键字:abstract、assert、boolean、break、byte、case、catch、char、class、continue、default、do、double、else、enum、extends、final、finally、float、for、if、implements、import、int、interface、instanceof、long、native、new、package、private、protected、public、return、short、static、strictfp、super、switch、synchronized、this、throw、throws、transient、try、void、volatile、while。

2)2个保留字(现在没用以后可能用到作为关键字):goto、const。

3)3个特殊直接量:true、false、null。

标识符注意点:1. 首字符可以是字母,美元符,下划线。

  1. 不能使用关键字作为变量名或方法名。
  2. 标识符是大小写敏感的。
String $money="64";//初始化
System.out.println($money);

数据类型

java的数据类型主要分为两大类:基本类型,引用类型。
基本数据类型包括:数值类型(byte,short,int,long,float,double,char(2字节)),boolean类型(占1位,其值只有truefalse两个)
引用数据类型包括:类,接口,数组
float num5=50.1F;//float类型要加F
long num3=30L;//long类型要在数字后加L
byte num4=20;
int num99=010;//八进制
int num66=0x10;//十六进制
int k=100_000_000;//JDK7新特性,数字之间可以用下划线分割
double s=1.234E-2;//1.234*(10^-2)
double ll=99.99;
char name='请';
//字符串String不是关键字,而是类
String namea="秦疆";
//布尔值
boolean b=true;
//Boolean类
Boolean flag=true;//Boolean类的实例,而不是boolean类型
if(flag instanceof Boolean){//判断是不是Boolean的实例
    System.out.println("yes");
}
//数组声明
int[]  nums;
int nums2[];
//数组创建(默认初始化)
nums=new int[10];
或者:int[] nums=new int[10];
//静态初始化
int[] a={1,2,3};
Man[] mans={new Man(1,1),new Man(2,2)};
Class[] paramTypes=new Class[]{String.class,String.class};//元素为Class类的数组
//动态初始化
int[] a=new int[2];
a[0]=1;
a[1]=2;
//数组赋值
for(int i=0;i<nums.length;i++)
{//nums.length自动读取数组长度
    nums[i]=i;
}
for(int i:nums){
    //nums.for加回车就能生成类似这个
    //nums是一个数组,i是数组的每一个元素
    System.out.print(i+" ");
}

注意:浮点数会有精度问题,所以如果需要运算的话一般用BigDecimal数学工具类

输入输出

Scanner对象的方法包括nextByte(),nextShoret(),nextInt(),nextLong(),nextFloat(),nextDouble()
    可以通过next()nextLine()方法获取字符串,读取前我们一般用hasNext()hasNextLine()判断是否还有输入数据
next()
1. 一定要读取到有效字符后才可以结束输入
2. 对有效字符前面遇到空白,next()方法会自动去掉
3. 只有输入有效字符后才将后面输入的空白(空格)作为分隔符或结束符
4. next()不能得到带有空格的字符串

nextLine()
1.Enter位结束
2. 可以获取空白
import java.util.Scanner;
import java.util.InputMismatchException;
//计算圆面积
public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        final double PI = 3.1415926;
        // 提示用户输入半径
        System.out.print("请输入圆的半径(整数):");
        try {
            // 检查是否有整数输入
            if (input.hasNextInt()) {
                int r = input.nextInt();
                // 检查半径是否为非负数
                if (r >= 0) {
                    // 计算面积并格式化输出
                    double area = PI * Math.pow(r, 2);
                    System.out.printf("圆的面积是:%.2f%n", area);
                } else {
                    System.out.println("半径不能为负数!");
                }
            } else {
                System.out.println("请输入一个有效的整数!");
            }
        } catch (InputMismatchException e) {
            // 捕获并处理非整数输入异常
            System.out.println("输入错误,请输入一个整数!");
            // 清除输入错误标记
            input.next(); // 消耗掉错误的输入
        } finally {
            // 关闭Scanner以释放资源
            input.close();
        }
    }
}

1. 流程互动

if...else if...else
while(){}
do{}while()
for (int item : numbers) {
    System.out.println("Count is:" + item);
}
char grade='c';
switch(grade){
    case 'a':System.out.println("niu");break;
        case 'b':System.out.println("liang");break;
        case 'c':System.out.println("xing");break;
        case 'd':System.out.println("buxing");break;
        case 'e':System.out.println("ji");break;
    default:System.out.println("shen");break;
}

2. 方法

命令行传参

package com.kuang.method
public static void main(String[] args) {
        int a=1,b=2;
  		for(int i=0;i<args.length;i++){
             System.out.println(args[i]);
        }
}
//命令行先在路径为包里面javac demotwo.java
//然后在路径为src里java com.kuang.method.demotwo
this is kuang

可变参数

public class Demo4{
    public static void main(String[] args){
        demott demo4=new demott();
        demo4.test(1,61,62,63,64,65);
    }
    public void test(int x,int... i){
        for(int m:i){
            System.out.print(m+" ");
        }
    }
}

方法重载

public int add(int a,int b){
        return a+b;
}
public double add(double a,double b){
    return a+b;
}

3. 面向对象

1. 构造器,继承,重写

注意:父类权限,子类不能重写static,final,private方法

package com.jk.cc;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import java.io.IOException;
import java.lang.reflect.*;
import java.lang.Boolean;
public class cc1test {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Child child1 = new Child("123");
        child1.say("hello");
        // 输出:
        //父类有参构造:123
        //Child constructor with message called
        //666
        //hello
    }

}
class Parent {
    String message;//成员变量
    // 父类构造器
    Parent() {
        System.out.println("Parent constructor called");
    }

    Parent(String message) {
        this.message=message;
        System.out.println("父类有参构造:"+this.message);
    }
    public void say(String name){
        System.out.println("666");
    }
}

class Child extends Parent {
    // 子类构造器,调用父类的无参构造器(隐式调用,如果父类有无参构造器)
    // 或者显式调用:super();

    Child() {
        // 隐式调用Parent()
        System.out.println("Child constructor called");
    }

    // 子类构造器,显式调用父类的带参构造器
    Child(String message) {
        super(message); // 子类调用父类构造器必须在第一行
        //显式调用Parent(String message)
        System.out.println("Child constructor with message called");
        //调用父类方法
        super.say("123");
    }
    @Override
    public void say(String name){//子类重写父类方法
        System.out.println(name);
    }
}

2. 多态

多态(向上转型,向下转型)

1. 多态是方法的多态,属性没有多态
2. 父类和子类有联系
3. 存在条件:有继承关系,方法需要重写,父类引用指向子类对象
4. 子类转换为父类可能丢失本来方法
    
//向上转型,即父类的引用指向子类的对象
/*
编译类型看左边,运行类型看右边
可以调用父类的所有成员(需遵守访问权限)
不能调用子类的特有成员
运行效果看子类的具体实现
*/
父类类型 引用名 = new 子类类型();
//右侧创建一个子类对象,把它当作父类看待使用

//向下转型(高转低),即一个已经向上转型的子类对象,将父类引用转为子类引用
/*
特点:
只能强制转换父类的引用,不能强制转换父类的对象
要求父类的引用必须指向的是当前目标类型的对象
当向下转型后,可以调用子类类型中所有的成员
*/
语法
子类类型 引用名 = (子类类型) 父类引用;
//用强制类型转换的格式,将父类引用类型转为子类引用类型
//这里的子类可以是实现类,父类可以是接口
if(animal instanceof  Cat){
    Cat c=(Cat)animal;
    System.out.println(c.name);
}
//演示代码
public class demott {


    public static void main(String[] args) {
        //向上转型(自动类型转换)
		//程序在编译阶段只知道 p1 是 Person 类型
		//程序在运行的时候才知道堆中实际的对象是 Student 类型
        Person p1 = new Student();

        //调用的是 Student 的 mission
        //程序在编译时 p1 被编译器看作 Person 类型
		//因此编译阶段只能调用 Person 类型中定义的方法
		//在编译阶段,p1 引用绑定的是 Person 类型中定义的 mission 方法(静态绑定)
		//程序在运行的时候,堆中的对象实际是一个 Student 类型,而 Student 类已经重写了 mission 方法
		//因此程序在运行阶段对象中绑定的方法是 Student 类中的 mission 方法(动态绑定)
        p1.mission();
        
        //向下转型
        Student s1 = (Student)p1;

        //调用的是 Student 的 score
        s1.score();
    }

}
 class Person {
    public   void mission() {
        System.out.println("人要好好活着!");
    }
}
class Student extends Person {
    public   void mission() {
        System.out.println("学生要好好学习!");
    }
    public void score() {
        System.out.println("学生得到好成绩!");
    }
}
class Teacher extends Person {

    public  void mission() {
        System.out.println("老师要好好教书!");
    }
    public void salary() {
        System.out.prinjavatln("老师得到高工资!");
    }
}

3. 接口

1. 接口可以多继承
2. 只有规范
3. 接口中所有定义都是抽象的public abstract
4. 类可以实现接口
5. 必须重写接口中的方法
6. Java语言中,接口是不能创建对象的。(据说)
7. 接口不能被实例化。
8. 接口没有构造方法和静态代码块
9. 父类方法跟接口方法冲突时,执行父类方法
10. 接口里的静态方法可直接用`接口名.方法名()`调用
// 定义第一个接口
interface Swimmer {
    void swim();
}
// 定义第二个接口
interface Flyer {
    void fly();
}
// 定义一个类来实现上述两个接口
class SuperCreature implements Swimmer, Flyer {
    // 实现Swimmer接口中的方法
    @Override
    public void swim() {
        System.out.println("Swimming...");
    }
    // 实现Flyer接口中的方法
    @Override
    public void fly() {
        System.out.println("Flying...");
    }
    // 可以定义类自己的方法
    public void eat() {
        System.out.println("Eating...");
    }
}
// 测试类
public class TestInterfaces {
    public static void main(String[] args) {
        // 创建SuperCreature对象
        SuperCreature creature = new SuperCreature();
        // 调用实现的方法
        creature.swim(); // 输出:Swimming...
        creature.fly();  // 输出:Flying...
        // 调用类自己的方法
        creature.eat();  // 输出:Eating...
    }
}

4. 泛型

泛型标记符

E - Element (在集合中使用,因为集合中存放的是元素)
T - TypeJava 类)
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的 java 类型 

泛型类与泛型方法

public class cc1test {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Test t1 = new Test();
        /*
        100
        hello
        5.9
        Cat{}
        * */
        System.out.println(Adder.add(1.5,3.9));//5.4
    }
}
class Printer<T>{
    private T toPrint;
    public Printer(T toPrint) {this.toPrint = toPrint;}
    public void print() {System.out.println(toPrint);}
}
class Test{
    public Test(){
        Printer<Integer> integerPrinter=new Printer<Integer>(100);
        integerPrinter.print();
        Printer<String> stringPrinter=new Printer<>("hello");
        //右侧<>是类型推断的语法糖,左侧已经提供类型了,这里不用再次指定
        stringPrinter.print();
        Printer<Double> doublePrinter=new Printer<>(5.9);
        doublePrinter.print();
        Printer<Cat> catPrinter=new Printer<>(new Cat());
        catPrinter.print();
    }
}
class Cat{
    @Override
    public String toString() {
        return "Cat{}";
    }
}
class Adder{
    public static <T extends Number> double add(T t1, T t2) {
        return t1.doubleValue()+t2.doubleValue();
    }
}

PECS原则

PECS producer extends consumer super

生产者(Producer)用 extends,消费者(Consumer)用 super

List<? extends Number> 
//允许赋值类型Number或Number的子类
//可以从list读取元素作为数据的提供者,但不能添加元素(除了null)

List<? super Number> 
//允许赋值类型Number和Number的父类
//可以向list写入元素作为数据的消费者,但不能获取特定元素(除了Object类型)

泛型extends与super(协变与逆变)

  • <? extends T> 是协变的,这意味着如果 Apple 是 Fruit 的子类,那么 List<Apple> 也是 List<? extends Fruit> 的子类型。

  • <? super T> 是逆变的,这意味着如果 Fruit 是 Apple 的父类,那么 List<Fruit> 也是 List<? super Apple> 的父类型。

  • List<String>不是List<Object>的子类

package com.jk.cc;
import com.alibaba.fastjson.JSON;
import java.io.Serializable;
import java.util.*;
import java.lang.reflect.*;

public class cc1test {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        ArrayList<Object> list = new ArrayList<>();
        ArrayList<String> list1 = new ArrayList<>();
        //下面这行会报错,除非ArrayList<? extends Object> list = new ArrayList<>();
        //list=list1;

        List<Double> s1= new ArrayList<>();
        s1.add(1.1);
        s1.add(3.3);
        s1.add(2.2);
        Test2.sort(s1);
        System.out.println(JSON.toJSON(s1));
        //[1.1,2.2,3.3]

        List<Integer> s2 = new ArrayList<>(2);
        s2.add(Integer.valueOf("-5"));
        Filter<Number> filter = new Filter<Number>() {
            //new了一个实现该接口的匿名内部类
            @Override
            public boolean test(Number number) {
                return number.doubleValue()>0D;//双精度0
            }
        };
        Test2.removeIf(s2,filter);
        System.out.println(s2);//-5
    }
}
class TestGeneric<E extends Object & Serializable & Runnable & Comparable>{
    //意思是E继承Object类且实现了Serializable & Runnable & Comparable接口
}
interface Filter<E>{
    public boolean test(E e);
}
class Test2{
    public static <E> List<E> removeIf(List<E> list, Filter<? super E> filter) {
        //<E>是类型声明,List<E>是返回类型
        List<E> toRemove = new ArrayList<>();
        for (E e : list) {
            if (filter.test(e)) {
                toRemove.add(e);
            }
        }
        list.removeAll(toRemove);
        return toRemove;
    }
    public static void sort(List<? extends Number> toSortList ){
        //下面这行会报错
        //toSortList.add(Integer.valueOf(10));
        if(toSortList != null && toSortList.isEmpty()){
            return;
        }
        Collections.sort(toSortList,Comparator.comparingInt(Number::intValue));
        //Comparator.comparingInt是一个静态方法,用于创建一个比较器,该比较器根据提供的函数返回的整数值来对对象进行排序。
        //Number::intValue是一个方法引用,它引用了Number类(或其子类)的intValue方法。
        //intValue方法将Number对象转换为int类型。(2.7会变成2)
    }
}

泛型指定

maven库添加

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.47</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.3</version>
</dependency>
package com.jk.cc;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.HashMap;
import java.io.IOException;
import java.lang.reflect.*;

public class cc1test {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        JsonTest c= new JsonTest();//{Alex=35000.0, Eric=5000.0}
    }
}
class JsonTest {
    public JsonTest(){
        this.testwithGenericInCollection();
    }
    public void testwithGenericInCollection(){
        HashMap<String,Double>map= new HashMap<>();
        map.put("Alex",35000D);
        map.put("Eric",5000D);
        // 使用fastjson将HashMap序列化为JSON字符串
        String jsonStr = JSON.toJSONString(map);
        JSONObject object =JSON.parseObject(jsonStr);
        // 确定反序列化结果的泛型参数
        // 使用jackson的反序列化功能,根据提供的TypeReference确定反序列化结果的泛型参数
        HashMap<String,Double> fromJson= getFromJson(jsonStr,new TypeReference<HashMap<String,Double>>(){});
        System.out.println(fromJson);
    }
    public <T> T getFromJson(String str, TypeReference<T> typeReference){
        //<T>是一个类型参数声明,它告诉编译器 T 是一个泛型类型
        //T表明了方法的返回类型
        ObjectMapper objectMapper= new ObjectMapper();
        try{
            return objectMapper.readValue(str,typeReference);
        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }
}

5. 注解和反射

常见元注解

@Retention
用于指定被它注解的注解保留的时间。
RetentionPolicy.SOURCE:注解仅在源代码中保留,编译后不会保留。
RetentionPolicy.CLASS:注解在编译时被保留,但在运行时不会被加载到 JVM 中(这是默认行为)。
RetentionPolicy.RUNTIME:注解在运行时被保留,并且可以通过反射机制读取。

@Target
用于指定被它注解的注解可以应用的地方。
ElementType.METHOD:表示方法声明。注解可以应用于方法上。
ElementType.FIELD:表示字段声明(包括枚举常量)。注解可以应用于类的成员变量上。
ElementType.PARAMETER:表示形式参数声明。注解可以应用于方法的参数上。
ElementType.CONSTRUCTOR:表示构造器声明。注解可以应用于类的构造方法上。
ElementType.LOCAL_VARIABLE:表示局部变量声明(注意,Java注解在Java 8之前不能用于局部变量,从Java 8开始支持)。
ElementType.ANNOTATION_TYPE:表示注解类型声明。注解可以应用于其他注解的定义上。
ElementType.PACKAGE:从 Java 9 开始,注解可以应用于包声明。这允许注解被用于整个包级别。
ElementType.TYPE_PARAMETERJava 8 引入):表示类型参数声明。注解可以应用于泛型类型参数上。
ElementType.TYPE_USEJava 8 引入):表示类型的使用。这允许注解应用于任何类型的使用上,如泛型、强制类型转换等。
    
@Inherited
用于指定被它注解的注解是否可以被子类继承

自定义注解

public class cc1test {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        AnnotationTests annotationTests = new AnnotationTests();
        annotationTests.annotationTrick();
        //true
		//cat!
    }
}
@AnnotationTests.Pet(value="cat!")
class Cat{
    String name;
}
class AnnotationTests{
    @Target({ElementType.TYPE,ElementType.LOCAL_VARIABLE,ElementType.METHOD}) //Target元注解有value成员变量
    @Retention(RetentionPolicy.RUNTIME) //保留策略,运行时仍然可用
    public @interface Pet{//自定义注解
        //注解头上有注解
        String value();
    }
    @Pet(value="cat")
    public void testPetAnnotation(){
        @Pet(value="cat")
        Cat cat = new Cat();
    }

    public void annotationTrick(){
        Cat cat = new Cat();
        Class<? extends Cat> catClazz=cat.getClass();
        boolean annotationPresent = catClazz.isAnnotationPresent(Pet.class);//判断类是否有注解
        System.out.println(annotationPresent);
        Pet annotation = catClazz.getAnnotation(Pet.class);
        if(annotation!=null){
            System.out.println(annotation.value());
        }
    }
}

Class对象类的获取

import java.lang.Class;
//1.根据类名:类名.class
Class userClass =User.class;
//2.根据对象:对象.getClass()
User user=new User();
Class ac=user.getClass();
//3.根据全限定类名:Class.forname("全路径名")
Class ac=Class.forName("com.example.demo1.User");
//4.通过类加载器获取Class对象:
//ClassLoader.getSystemClassLoader().loadClass("com.example.demo1.User");
ClassLoader clsload=ClassLoader.getSystemClassLoader();
Class ac2=clsload.loadClass("com.example.demo1.User");

获取成员变量

import java.lang.Class;
import java.lang.reflect.Field;
//Class类中用于获取成员变量的方法
Field[] getFields()://返回所有 公共 成员变量对象的数组
Field[] getDeclaredFields()://返回所有成员变量对象的数组
Field getField(String name)://返回单个公共成员变量对象
Field getDeclaredField(String name)://返回单个成员变量对象
    
//Field 类中用于创建对象的方法
void set(Object obj,Object value):赋值
Object get(Object obj)获取值。

//Class类中用于获取构造方法的方法
Constructor<?>[] getConstructors(): 返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors(): 返回所有构造方法对象的数组
Constructor<T>[] getConstructor(Class<?>... parameterTypes): 返回单个公共构造方法对象
Constructor<T>[] getDeclaredConstructor(Class<?>... parameterTypes):
    //返回单个构造方法对象

//Constructor类中用于创建对象的方法
T newInstance(Object... initargs): 根据指定的构造方法创建对象
setAccessible(boolean flag): 设置为true,表示取消访问检查

        
//Class类中用于获取成员方法的方法
Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>... parameterTypes) :返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回单个成员方法对象

//Method类中用于创建对象的方法
Object invoke(Object obj, Object... args):
运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)

参考代码

Class ac1=Class.forName("java.lang.Runtime");
Method exec1=ac1.getMethod("exec", String.class);
Method getRuntime1=ac1.getMethod("getRuntime");
Object runtimeObject=getRuntime1.invoke(ac1);
exec1.invoke(runtimeObject, "calc.exe");

6. 代理对象

​ 在Java中,代理对象(Proxy Object)是一种设计模式,用于在运行时创建一个类的代理,以便控制对这个类的访问。代理对象通常用于实现访问控制、远程方法调用、延迟初始化等场景。

1. 静态代理

静态代理是代理模式的一种简单实现方式,它要求程序员手动为每个类编写代理类。例如:

interface Subject {
    void request();
}

class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("Executing request");
    }
}

class ProxySubject implements Subject {
    private RealSubject realSubject;

    public ProxySubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        System.out.println("Pre-processing before request");
        realSubject.request();
        System.out.println("Post-processing after request");
    }
}

public class helloTest {
    public static void main(String[] args) {
        ProxySubject proxySubject = new ProxySubject(new RealSubject());
        proxySubject.request();
    }
}

2. 动态代理

Java的动态代理机制允许在运行时动态地创建代理类和实例,而不需要手动编写每个代理类的代码。这主要通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口实现。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface InterfaceToProxy {
    void methodToCall();
}

class RealObject implements InterfaceToProxy {
    @Override
    public void methodToCall() {
        System.out.println("Called methodToCall");
    }
}

class MyInvocationHandler implements InvocationHandler {//InvocationHandler接口实现方法调用拦截
    private final Object target;

    public MyInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //proxy代表当前被调用的动态代理对象实例本身,是JVM生成的代理类的实例。
        //当通过代理对象调用方法时,该参数会传入对应的代理实例引用
        System.out.println("Before method: " + method.getName());
        Object result = method.invoke(target, args); // 反射调用实际对象的方法
        System.out.println("After method: " + method.getName());
        return result;
    }
}

public class helloTest {
    public static void main(String[] args) {
        RealObject realObject = new RealObject();
        InterfaceToProxy proxyInstance = (InterfaceToProxy) Proxy.newProxyInstance(
                InterfaceToProxy.class.getClassLoader(),
                //类加载器,负责将动态生成的代理类字节码加载到JVM中,使其成为可执行的Java对象,确保代理类可被JVM识别
                new Class<?>[] { InterfaceToProxy.class },
            	//代理接口数组,代理类将实现这些接口的所有方法,并通过InvocationHandler拦截调用
                new MyInvocationHandler(realObject));
        		//调用处理器,通过包装目标对象,实现对方法调用的拦截控制
        proxyInstance.methodToCall(); // 输出将会显示调用前后的信息,而实际的方法调用发生在真实对象上。
        //代理对象将方法调用转发给MyInvocationHandler.invoke()
    }
}

7. AOP编程

1. 简介

**Java AOP(面向切面编程)**‌是一种编程范式,旨在通过预编译或运行时动态代理的方式,将横跨多个模块的功能(如日志、事务管理、安全控制等)与业务逻辑分离,从而减少代码重复、提高代码的可维护性和可重用性。

AOP的核心概念包括:

  • ‌**切面(Aspect)**‌:包含一组通知的类,用于定义横跨多个类型的行为或横切关注点。
  • ‌**连接点(JoinPoint)**‌:程序执行过程中能够插入切面定义的行为的点,通常是方法调用。
  • ‌**通知(Advice)**‌:在特定的连接点上执行的动作,包括前置通知、后置通知、异常通知等。
  • ‌**切入点(Pointcut)**‌:匹配连接点的条件表达式,定义了哪些连接点会被通知。

注意:静态方法不能进行AOP(面向切面编程)。

匿名函数不能加注解。

常用注解

@Aspect:用于定义切面类。
@Before:在目标方法执行前执行。
@After:在目标方法执行后执行。
@Around:环绕通知,可以在方法执行前后进行自定义处理。
@AfterReturning:在方法正常返回后执行。
@AfterThrowing:在方法抛出异常时执行。

2. idea配置参考

idea的pom.xml参考

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
        <relativePath/>
    </parent>
    <groupId>com.itheima</groupId>
    <artifactId>springcache-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId><!--主要依赖1-->
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>

        <dependency>
            <groupId>commons-lang</groupId><!--提供丰富的工具类和方法-->
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.1</version>
        </dependency>

        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>3.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId><!--主要依赖2-->
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.7.3</version>
            </plugin>
        </plugins>
    </build>
</project>

application.yml

server:
  port: 8888
spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/spring_cache_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
      username: root
      password: 123456
  redis:
    host: localhost
    port: 6379
    password: 123456
    database: 1
logging:
  level:
    com:
      itheima:
        mapper: debug
        service: info
        controller: info

3. 代码编写

启动类com/itheima/AOPDemoApplication.java

package com.itheima;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@Slf4j //提供日志记录,比如log.info函数
@SpringBootApplication
public class AOPDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(AOPDemoApplication.class,args);
        log.info("项目启动成功...");
    }
}

com/itheima/controller/TestAOPController.java

package com.itheima.controller;

import com.itheima.Service.TestAOPService;
import com.itheima.entity.Ticket;
import io.swagger.annotations.Api;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.Serializable;

@Data //自动生成getter和setter
class Result<T> implements Serializable {
    private Integer code; //编码:1成功,0和其它数字为失败
    private String msg; //错误信息
    private T data; //数据

    public static <T> Result<T> success() {//第一个<T>使success成为泛型方法
        Result<T> result = new Result<T>();
        result.code = 1;
        return result;
    }

    public static <T> Result<T> success(T object) {
        Result<T> result = new Result<T>();
        result.data = object;
        result.code = 1;
        return result;
    }

    public static <T> Result<T> error(String msg) {
        Result result = new Result();
        result.msg = msg;
        result.code = 0;
        return result;
    }
}

@RestController //会自动将方法返回值通过HttpMessageConverter转换为JSON格式
@RequestMapping("/aop")
@Api("AOP编程示例")
public class TestAOPController {

    @Autowired //防止new对象绕过Spring代理,导致AOP拦截失败
    private TestAOPService testAOPService;

    @GetMapping("/test")
    public Result<Ticket> testAOP(){

        Ticket ticket=testAOPService.testAOP(new Ticket());
        return Result.success(ticket);
    }

}

com/itheima/Service/TestAOPService.java

package com.itheima.Service;

import com.itheima.annotation.AutoFill;
import com.itheima.entity.Ticket;
import org.springframework.stereotype.Service;

@Service
public class TestAOPService {

    @AutoFill(value="自动填充参数")
    public Ticket testAOP(Ticket ticket) {
        return ticket;
    }
}

com/itheima/annotation/AutoFill.java

package com.itheima.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解,用于标识某个方法需要进行功能字段自动填充处理
 */
@Target(ElementType.METHOD) //该注解只能用于方法级别
@Retention(RetentionPolicy.RUNTIME) //注解在运行时可通过反射获取
public @interface AutoFill {
    String value();

}

自定义切面类com/itheima/aspect/AutoFillAspect.java

package com.itheima.aspect;


import com.itheima.annotation.AutoFill;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 自定义切面类,实现字段自动填充逻辑
 */
@Aspect //定义一个切面类
@Component //注册为Spring Bean
@Slf4j //生成一个基于 SLF4J(Simple Logging Facade for Java)的日志对象 log
public class AutoFillAspect {
    /**
     * 切入点
     */
    @Pointcut("execution(* com.itheima.Service.*.*(..)) && @annotation(com.itheima.annotation.AutoFill)")
    //第一个*表示任意返回类型, (..)表示任意参数列表
    //定义了一个Spring AOP切入点,匹配Service包下所有的含@AutoFill注解的类和方法
    public void autoFillPointCut() {
        log.info("AutoFillPointCut");
    }

    /**
     * 定义通知:在切入点上定义增强处理,主要有五种通知类型:@Before、@After、@AfterReturning、@AfterThrowing和@Around
     * 前置通知,在通知中进行公共字段赋值
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) {//joinpoint表示程序执行过程中的一个连接点(JoinPoint),如方法调用、异常抛出等。
        log.info("开始进行字段自动填充...");

        //获取到当前被拦截的方法上的value
        MethodSignature signature=(MethodSignature) joinPoint.getSignature();//方法签名对象
        AutoFill autoFill =signature.getMethod().getAnnotation(AutoFill.class);//获得方法的注解对象
        String string=autoFill.value();//获取value的值
        System.out.println(string);

        //获取到当前被拦截的方法上的第一个参数,在本案例中是实体对象
        Object[] args = joinPoint.getArgs();
        if (args==null || args.length==0) {
            return;
        }

        Object entity=args[0];

        //准备赋值的数据
        LocalDateTime now=LocalDateTime.now();


        //为5个字段赋值
        try {
            //反射获取获取成员方法
            Method setId=entity.getClass().getDeclaredMethod("setId",int.class);//类型与Ticket的对应
            Method setPrice=entity.getClass().getDeclaredMethod("setPrice",double.class);
            Method setSeatNumber=entity.getClass().getDeclaredMethod("setSeatNumber",String.class);
            Method setIsUsed=entity.getClass().getDeclaredMethod("setUsed",boolean.class);
            //对于布尔类型字段isUsed,Lombok默认生成的setter方法名是setUsed()而非setIsUsed()
            Method setCreateTime=entity.getClass().getDeclaredMethod("setCreateTime",LocalDateTime.class);


            //反射赋值
            setId.invoke(entity,1);
            setPrice.invoke(entity,15);
            setSeatNumber.invoke(entity,"P1L5");
            setIsUsed.invoke(entity,false);
            setCreateTime.invoke(entity,now);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

com/itheima/entity/Ticket.java

package com.itheima.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.time.LocalDateTime;

@Data //是Lombok注解,生成getter,setter等
@NoArgsConstructor //生成无参构造方法
@AllArgsConstructor //生成全参数构造方法
public class Ticket implements Serializable {
    // 属性
    private int id;
    private double price;
    private String seatNumber;
    private boolean isUsed;
    private LocalDateTime createTime;
}

在这里插入图片描述

额外参考:https://javaguide.cn/home.html
https://www.xiaolincoding.com/

Instead we just blame the people /who are struggling for not working hard enough, all that does /is leave these people in a place /where they become humiliated(羞愧的) and resentful(愤慨的). Because from their perspective, all they’ve done is to go to school, get a degree, and do everything society told them to do. You know, they followed the recipe, and now they’re being told they can’t afford to function in the world.

–(美)迈克尔·桑德尔 《为什么“优绩主义”会腐蚀社会》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cllsse

富✌您吉祥

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值