java基础入门

快捷键

alt+insert 自动设置set/get/重写等方法

alt+enter 自动导入依赖包

javaSE学习

博客的重要性

  • 总结和思考
  • 更有效的记忆
  • 提升文笔组织能力

MarkDown语法

文件后缀 .md

常用的有标题,引用,列表,图片,超链接,无序列表,表格,代码

冯诺依曼体系结构

运算器,存储器,控制器,输入,输出

请添加图片描述

计算机软件

系统软件

操作系统:DOS(Disk Operating System),Windows, Linux, Unix, Android, IOS

应用软件

DOS命令

dir		#效果和ls一样
cd		#切换目录
cls		#清屏命令
exit	#退出
ipconfig#查看IP
md		#创建目录
rd		#移除目录
cd>文件名#创建文件
del		#删除文件

java特性

  • 简单
  • 面向对象
  • 可移植性,跨平台 Write Once, Run Anywhere
  • 分布式
  • 高性能

java三大版本:JavaSE标准版、JavaME嵌入式开发、JavaEE企业级开发

JDK、JRE、JVM的关系,从大到小的关系如下

  • JDK : Java Development Kit
  • JRE : Java Runtime Environment
  • JVM : Java Virtual Machine

第一个java程序

新建Hello.java文件,其内容如下

public class Hello {//Hello类名应该与文件名称Hello.java相同,否则会报错
    public static void main(String[] args) {
        System.out.print("Hello World!");
    }
}

在当前目录下打开cmd,输入如下命令

javac Hello.java #作用是使用javac进行编译,生成Hello.class文件
java Hello 	#作用是使用java运行字节码文件Hello.class文件,输出Hello World!
			#注意:写成java Hello.class会出错

注意:文件名和类型必须一致,并且首字母大写

java运行机制

编译型

解释型

java基础语法


注释

三种注释:单行注释、多行注释、文档注释

单行注释://

多行注释:/* */

文档注释:javaDoc

标识符

所有的标识符都应该以字母(A-Z或者a-z)、**美元符号($)**或者下划线(_)开始,

首字符之后可以是字母(A-Z或者a-z)、美元符号($)、下划线(_)或者数字的任何组合字符。

大小写敏感

数据类型

强类型语言:所有变量都必须先定义后才能使用,安全性高

java数据类型分为两大类

  • 基本类型

    类型名称占据空间大小,单位字节
    整数byte1
    整数short2
    整数int4
    整数long8
    浮点数float4
    浮点数double8
    字符char2
    布尔类型boolean1bit
    //long类型要在数字后面加个L
    long num1 = 300L;
    //float类型要在数字后面加个F
    float num2 = 50.1F; 
    
  • 引用类型

    类,接口,数组

类型转换

强制类型转换 高–>低

char c = 'a';
int a = (int)c;//强制转换类型

long aa = 234935234332L;
int bb = 12334;
short cc = 133;
byte dd = 23;
System.out.print(a + b + c + d); //输出是long类型
System.out.print(b + c + d);	//输出是int类型
System.out.print(c + d);		//输出是int类型,原因:没有long型时候,所有非int型转为int型

自动类型转换 低–>高 自动转换

注意:不能对布尔类型进行转换,布尔类型不能参与类型转换

变量

变量是基本的存储单元,要素包括变量名、变量类型和作用域

public class Demo {
    //类变量 static 从属于类
    static double salary = 20000.0;
    
    //实例变量:从属于对象,有默认值 0 0.0 null flase
    String name;
    int age;
    
    //main方法
    public static void main(String[] args) {
        //局部变量
        int i = 0;
        
        Demo demo = new Demo();
        System.out.print(demo.name);//String对象的默认值是null
        System.out.print(demo.age);
    }
    
    //其他方法
    public void func() {
        
    }
}

常量

初始化后不能再改变的值,在程序运行过程中不允许被改变, 关键字final

final 类型 常量名 =;
final double PI = 3.14;//常量名一般用大写字符

运算符

算术运算符 +、-、*、/、%、++、–

赋值运算符 =

关系运算符 >、<、>=、<=、==、!=

逻辑运算符 &&、||、 !

逻辑运算符具&&和II有短路性质

位运算符 &(按位与)、|(按位或)、^(按位异或)、~(按位取反)、>>、<<、>>>

条件运算符 ?:

扩展运算符 +=、-=、*=、/=

int a = 10;
int b = 20;
//字符串连接使用“+”
System.out.print("" + a + b);//输出1020
System.out.print(a + b + "");//输出30

包机制

为了更好的组织类,java提供了包机制,用于区别类名的命名空间

包语句的语法格式如下

package pkg1[.pkg2[.pkg3···]];
//该语句必须在整个类的最开始处

一般利用公司域名倒置作为包名,如com.baidu.www

使用import语句导入包

import package1[.package2···].(classname|*);//*号代表所有

javaDoc

javadoc命令可以用来生成自己的API文档,使用命令如下

javadoc -encoding utf-8 -charset utf-8 HelloWorld.java

常用的注解 参数信息

// 在方法上输入/**然后回车,即可生成注解
/*
@author 作者名
@version 版本号
@since 指明需要最早使用的jdk版本 如1.8
@param 参数名
@return 返回值情况
@throws 异常抛出情况
*/

java流程控制

  • Scanner
import java.util.Scanner;
//从键盘接收数据
Scanner scan = new Scanner(System.in);
//接受输入
String str = scan.next();
System.out.println(str);
//注意,使用完之后一定要关闭
scan.close();
  • 顺序结构

  • if选择结构

  • switch case选择结构

  • while循环结构

  • do while循环结构

  • for循环结构

    for (int num : nums)
    {
        System.out.println(num);
    }
    for (int )
    

Java方法

方法

java方法的命名规则:首字母小写+驼峰命名法,如

方法包含于类或者对象中,在程序中创建,在其他地方被引用

设计方法时候最好保持方法的原子性,一个方法只完成一个功能

修饰符 返回值类型 方法名(参数类型 参数名) {
	···
    方法体
    ···
    return 返回值;
}

参数列表指的是方法的参数类型、顺序和参数个数

调用方法:对象名.方法名(实参列表)

值传递

java只有值传递

方法重载

重载是在一个类中,有相同的函数名称,但是形参不同的函数

重载规则如下:

  • 方法名称必须相同
  • 参数列表不同(个数,类型或者排列顺序不同)
  • 方法的返回类型可以相同也可以不同
  • 仅返回类型不同不是重载, 会报错,原因:方法重定义

方法名称相同时候,编译器会根据调用方法的参数个数,参数类型去逐个匹配,如果匹配失败会报错

命令行传参

//通过main方法传入参数
public static void main(String[] args) {
    for (int i = 0; i < args.length; i ++)
    {
        System.out.println("args[" + i + "]:" + args[i]);
    }
    return;
}

运行方法:

首先在命令行用javac将.java代码编译成.class文件,然后跳转到src目录下,使用java命令运行,此时文件需要带包前缀,并在后面跟上自己要传入的参数

java test.CommandLine this is test//test是包名,里面有CommandLine类

可变参数

JDK1.5开始,Java支持传递同类型的可变参数的一个方法,在指定参数类型后加一个省略号(…)

一个方法中只能制定一个可变参数 ,它必须是方法的最后一个参数,任何普通参数必须在它之前声明

public static void main(String[] args) {
    int max = getMax(1,2,3,4,5);
    System.out.print(max);
    return;
}
public static int getMax(int... x)//可变参数,在参数类型后加...
{
    int res = 0;
    for (int i = 0; i < x.length; i ++)
        if (res < x[i]) res = x[i];
    return res;
}

递归

递归结构包括两个部分:

  • 递归头:什么时候不调用自身方法。如果没有头,将陷入死循环
  • 递归体:什么时候需要调用自身方法

数组

数组

数组是相同类型数据的有序集合,通过下标来进行访问

数组声明方法:

//使用new操作符来创建数组
dataType[] arrayRefVar = new dataType[arraySize];
int[] array = new int[10];//创建长度为10的int型数组

数组的特点

下标的合法区间[0, nums.length - 1],如果越界会报错

ArrayIndexOutOfBoundsException:数组下标越界异常

数组的三种初始化方式

  • 静态初始化

    int[] nums = {1,2,3};
    Man[] mans = {new Man("Jerry"), new Man("Tom")};
    
  • 动态初始化

    int[] nums = new int[10];//此时每个元素被隐式初始化为0;
    int[] nums2 = new int[]{1,2,3,4,5};//使用元{元素}初始化时候,不能指派数组的长度,不然报错
    
  • 数组的默认初始化

    数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素都会被隐式初始化为默认值。

二维数组

int[][] nums = new int[2][3];//定义2行3列二维数组
int[][] nums = new int[][]{{1,2},{3,4},{5,6}};
for (int i = 0; i < nums.length; i ++)
	for (int j = 0; j < nums[0].length; j ++)
		System.out.print(nums[i][j] + " ");

Arrays工具类

import java.util.Arrays;
int[] a = new int[]{3,2,56,6};
Arrays.sort(a);//调用Arrays工具类对数组进行排序
System.out.print(Arrays.toString(a));//以字符串的形式输出数组
//输出如下
[2, 3, 6, 56]

排序算法

  • 冒泡排序

稀疏数组

原因:因为该二维数组中很多默认值是0,因此记录了很多没有意义的数据,解决方案使用稀疏数组
请添加图片描述

左边是原始矩阵,右边是压缩过的稀疏矩阵

面向对象编程

面向对象

面向对象的思想:物以类聚

OOP:Object-Oriented Programming 面向对象编程

三大特征:封装,继承,多态

对象是类的实例化,是具体的事物,类是对象的抽象。

类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是不能代表一个具体的事物。

创建对象

  • 使用new关键字创建对象

    Dog dog = new Dog();//dog是一个引用变量名,真正的数据存放在堆区
    

请添加图片描述

使用new创建对象时候,除了分配内存之外,还会给创建好的对象进行默认的初始化及对类中构造器的调用

类中会自动生成无参默认构造器,如果自定义构造器之后,则原来的无参构造器就不存在了

构造方法的特点如下:

  • 必须和类的名字相同
  • 必须没有返回类型
public class Student {
    String name;
    int age;
    public Student(String _name, int _age)
    {
        this.name = _name;//也可以不写this
        age = _age;
    }
}
  • 类里面包含两种东西:静态的属性动态的方法

封装

通常应该禁止直接访问一个对象中数据的实际表示,而应该通过接口操作来访问,这称为信息隐藏

高内聚,低耦合

属性私有,使用get/set来进行访问/设置

私有private

封装的好处:

  • 提高程序的安全型
  • 隐藏代码的实现细节
  • 统一接口
  • 系统可维护性增加

继承

所有类都直接或者间接继承Object类

关键字extends,子类继承父类,使用关键字extends来表示

java只有单继承,没有多继承,但一个类可以被多个类继承

public class Person {
    String name;
}

public class Doctor extends Person {//Doctor继承Person
    void fun();
}

super

super注意点

  • super调用父类的构造方法,必须在构造方法的第一个
  • super必须只能出现在子类的方法或者构造方法中
  • super和this不能同时调用构造方法

和this的区别

  • this代表调用者本身,super代表父类对象的引用
  • this没有继承也可以使用,super只在有继承条件下才使用
  • 构造方法:this()本类的构造,super()父类的构造
public class Person {
    String name;
    Person(String _name) {this.name = _name;}
}

public class Doctor extends Person {//Doctor继承Person
    String career;
    Doctor(String _name, String _career) {
        super(_name);
        this.carrer = _career;
    }
    void fun();
}

重写

在继承关系中,子类重写父类的方法

  • 方法名必须相同
  • 参数列表必须相同
  • 修饰符:范围可以扩大,但不能缩小:public > protected > default > private
  • 抛出的异常:范围可以被缩小不能被扩大:ClassNotFoundException --> Exception(大)

重写函数的快捷键操作:Alt + Insert,然后选择 override;会生成@Override注解

public class Person {
    public void eat() {System.out.println("Person eat")}
}
public class Doctor extends Person {
    @Override//表示是子类重写父类的方法
    public void eat() {
        System.out.println("Doctor eat");
    }
}

多态

同一方法可以根据发送对象的不同二采区多种不同的行为方式。

一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多(父类,有关系的类)

多态存在的条件

  • 有继承关系
  • 子类重写父类方法
  • 父类引用指向子类对象
Father f = new Son();//父类引用指向子类对象

final关键字:修饰的变量是常量,修饰的函数不能被重写

多态是方法的多态,属性没有多态

instanceof

作用:判断两个类之间是否存在父子关系,有父子关系返回true,没有返回false

//继承链如下:
//Object->Person->Student
//Object->Person->Teacher
Object obj = new Student();
System.out.println(obj instanceof Student);//true
System.out.println(obj instanceof Person);//true
System.out.println(obj instanceof Object);//true
System.out.println(obj instanceof Teacher);//false

//总结
System.out.println(X instanceof Y);
//如果X和Y之间不存在父子关系,则编译出错
//当满足父子关系时候,如果X的实际类型是Y类型或者其子类型时候,则返回true,否则返回false

static静态代码块

在类中,用static修饰的代码块只在类加载的时候执行一次,而不用static修饰的代码块则在创建对象时候都执行

public class Person {
    {
        System.out.println("匿名代码块");
    }
    static {
        System.out.println("静态代码块");
    }
    Person () {
        System.out.println("构造方法");
    }
    public static void main(String[] args) {
        System.out.println("===========");
        Person p1 = new Person();
        System.out.println("===========");
        Person p2 = new Person();
    }
}

//输入如下
静态代码块
===========
匿名代码块
构造方法
===========
匿名代码块
构造方法

抽象类

使用关键字abstract来表示

//使用关键字abstract表示某个类是抽象类
public abstract class Action {
    public abstract void func();//使用abstract表明某个方法是抽象方法,只有名字,没有实现
    //不能new抽象类,只能靠子类实现这个抽象方法之后,才能实例化对象
    public void do() {
        System.out.println("do");
    }
    //抽象类中可以写普通的方法
}

接口

接口里面只有方法的定义,没有方法的实现

使用interface关键字来定义接,使用implments关键字来实现接口的继承

//接口类使用interface关键字,此处没有class关键字
public interface Action {
    //接口中的所有量都是常量,是public static final的
    int AGE = 99;//等价与public static final int AGE = 99;
    
    //接口中的方法都是public abstract的
    void add();
    void delete();//等价于public abstract void delete();
}

//类可以实现接口,使用implements关键字
//实现了接口的类,要重写里面的方法
public class ActionImpl implements Action{
    @Override
    public void add() {
		System.out.println("add");
    }

    @Override
    public void delete() {
		System.out.println("delete");
    }
}

implements可以实现多个接口

接口不能被实例化,接口中没有构造方法

普通类vs抽象类vs接口

普通类:含有方法的具体实现

抽象类:含有抽象方法,无具体实现,也可以含有具体实现

接口:只有抽象方法(规范)

声明类的关键字是class,声明接口的关键字是interface

内部类

内部类就是在一个类内部再定义一个类,比如A类中定义一个B类,B类相对于A类来说就是内部类,而A类对B类来说就是外部类。

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类

一个java类中可以i有多个class类,但是只能有一个public class类

异常

java把异常当做对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类

主要分为两种错误Error和异常Exception

请添加图片描述

异常处理

  • 抛出异常
  • 捕获异常

异常处理五个关键字:try、catch、finally、throw、throws

int a = 1;
int b = 0;

try {								//try监控区域
    System.out.print(a / b);
}catch (ArtimeticException e) {		//catch 捕获异常
    System.out.print("程序出现异常,变量b不能为0");
}finally {							//处理善后工作,不管是否进行都会执行,可以进行一些资源的释放等等
    System.out.print("程序结束");
}

throw用于程序抛出异常
throws用于方法抛出异常

另外假设要捕获多个异常,从小到大,范围逐渐扩大,或者互不相交


Spring学习

spring官网手册

spring框架

spring

spring是一个轻量级控制反转(IOC)和面向切面(AOP)的容器框架

SSM:SpringMVC + Spring + Mybatis;

Spring的优点

  • 开源的免费框架
  • 轻量级、非入侵式的框架
  • 控制反转、面向切面编程
  • 支持事务,对框架整合的支持

spring组成

IOC理论推导

使用set接口实现

private UserDao userDao;

//利用set进行动态实现值的注入!
public void setUserDao(UserDao _userDao) {
    this.userDao = _userDao;
}

  • 之前,程序主动创建对象,控制权在程序员手上
  • 使用了set注入之后,程序不再具有主动性,而是变成了被动的接受对象!

附IOC简单模型源代码,程序结构如下:

三层结构

UserDao 接口

UserDaoImpl 实现类

UserService 业务接口

UserServiceImpl 业务实现类

请添加图片描述

其中代码为

//从上到下的代码依次为
public interface UserDao {
    void getUser();
}

public class UserDaoImpl implements UserDao{
    @Override
    public void getUser() {
        System.out.println("默认获取用户");
    }
}

public class UserDaoMysqlImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("Mysql获取用户");
    }
}

public class UserDaoOracleImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("Oracle 获取用户");
    }
}


public class UserDaoSqlserverImpl implements UserDao {
    @Override
    public void getUser() {
        System.out.println("Sqlserver获取用户");
    }
}

//业务层
public interface UserService {
    void getUser();
}

public class UserServiceImpl implements UserService{
    private UserDao user;
    //set注入实现控制反转
    public void setUserDao(UserDao _user) {
        this.user = _user;
    }
    @Override
    public void getUser() {
        user.getUser();
    }
}

//用户层,这样做的好处是将控制权转到用户层
public class MyTest {
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        //当想调用不同的UserDao方法时候,只需要使用set注入不同的UserDao实现类的对象
        ((UserServiceImpl) userService).setUserDao(new UserDaoSqlserverImpl());
        userService.getUser();
    }
}

IOC本质

**控制反转(IOC),是一种设计思想,DI(依赖注入)是实现IOC的一种方法。**没有loC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是loC容器,其实现方法是依赖注入(Dependency Injection,Dl)。

控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring之后,对象是由Spring来创建的

反转:程序本身不创建对象,而变成被动的接收对象

依赖注入:就是利用set方法来进行注入

IOC是一种编程思想,由主动的编程变成被动的接收

不用去程序中改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IOC:对象由Spring来创建、管理、 装配!

创建并使用Spring

创建Spring项目例子

配置bean.xml基本格式如下

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--com.java.spring5.User类中有两个属性,一个是age,另外一个是name-->
    <!--通过property设置属性的前提是类中含有该属性的set方法-->
    <!--配置User对象创建-->
    <bean id = "user" class = "com.java.spring5.User">
        <property name = "age" value = "3"/>
        <property name = "name" value = "tom" />
    </bean>
    
</beans>

java中调用bean.xml的用法

public static void main(String[] args) {
    //标准写法如下
    ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
    //从IOC容器中获取spring创建的user对象
    User user = (User)context.getBean("user");
    //调用user对象的show()方法
    user.show();
}

IOC创建对象的方式

  • 默认使用无参构造方法创建对象,之后使用标签来set对象内的参数

  • 当没有默认构造方法时候,必须使用有参构造对象时候,使用标签来设置参数

    • 下标赋值

      <bean id = "user2" class = "com.java.spring5.User">
          <constructor-arg index="0" value="3"/>
          <constructor-arg index="1" value="tom"/>
      </bean>
      
      
    • 类型赋值(不推荐,而且当含有相同类型的变量时候,该方法失效)

      <bean id = "user3" class = "com.java.spring5.User">
          <constructor-arg type="int" value="3"/>
          <constructor-arg type="java.lang.String" value="tom"/>
      </bean>
      
      
    • 参数名称赋值(推荐)

      <bean id="user" class="com.java.spring5.User">
          <constructor-arg name="age" value="3"/>
          <constructor-arg name="name" value="tom" />
      </bean>
      
      

总结:在配置文件加载的时候,容器中管理的 对象就已经初始化了!

Spring配置

alias别名

<!--别名,如果使用了别名,可以使用别名去获取到这个对象-->
<alias name="user" alias="userNew" />

bean配置

<!--
    id:bean的唯一标识符,也就是相当于我们的对象名称
    class:bean对象所对应的全限定名:包名+类型
    name:也是别名,而且name可以同时取多个别名
-->
<bean id="user" class="com.java.spring5.User" name="u,u2,u3">
    <property name="name" value="abc"/>
</bean>

import导入

import一般用于团队开发中,可以将多个配置文件,导入合并成一个总的

把beans1.xml、beans2.xml、beans3.xml导入到applicationContext.xml中,形成一个总的,这样使用的时候,直接使用总的就可以了

<import resource="beans1.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>

依赖注入

构造器注入

注入

set方式注入【重点】

注入

依赖注入

  • 依赖:bean对象的创建依赖于容器
  • 注入:bean对象中的所有属性,由容器来注入

举例:各种数据结构的注入方式

public class Address {
    private String address;

    public Address(String address)
    {
        this.address = address;
    }
	//此处set/get以及to_string等没有体现出来
}

public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbys;
    private Map<String, String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
	//此处set/get以及to_string等没有体现出来
}

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="address" class="com.java.demo1.Address">
        <constructor-arg name="address" value="四川成都"/>
    </bean>

    <bean id="student" class="com.java.demo1.Student">

        <!--String,使用value-->
        <property name="name" value="lufy"/>

        <!--引用另外的bean,使用ref-->
        <property name="address" ref="address"/>

        <!--数组-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>西游记</value>
                <value>水浒传</value>
            </array>
        </property>

        <!--List-->
        <property name="hobbys">
            <list>
                <value>唱歌</value>
                <value>跳舞</value>
            </list>
        </property>

        <!--Map-->
        <property name="card">
            <map>
                <entry key="身份证" value="111111222222223333"/>
                <entry key="银行卡" value="23423875927349729374823"/>
            </map>
        </property>

        <!--Set-->
        <property name="games">
            <set>
                <value>LOL</value>
                <value>植物大战僵尸</value>
            </set>
        </property>

        <!--null-->
        <property name="wife">
            <null/>
        </property>

        <!--Properties-->
        <property name="info">
            <props>
                <prop key="username">root</prop>
                <prop key="passward">123456</prop>
            </props>
        </property>
    </bean>

</beans>

扩展方式注入

可以使用p命名空间和c命名空间注入

注意:p命名和c命名空间不能直接使用,需要导入约束!

xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"

使用方法

<!-- p命名空间注入:可以直接注入属性的值:property -->
<bean id="user" class="com.java.demo.User" p:name="小明" p:age=18>
    
<!-- c命名空间注入:通过构造器注入:constructor-arg -->
<bean id="user2" class="com.java.deom.User" c:name="小红" c:age=18>

其实说白了就是set方式注入构造器注入的简化写法

bean的作用域

  • 单例模式:此时在java程序中利用getBean(“user”)获取两次,会得到同一个对象

    <bean id="user" class="com.java.demo.User" scope="singleton"/>
    
    
  • 原型模式:每次从容器中get时候,都会产生一个新对象!

    xxxxxxxxxx <bean id="user" class="com.java.demo.User" scope="prototype"/>
    
    
  • 其余的request、session、application,这些只能在web开发中使用

bean的自动装配

自动装配是Spring满足bean依赖的一种方式

Spring会自动在上下文中寻找,并自动给bean装配属性!

在spring中有三种装配的方式

<bean id="cat" class="com.java.Cat" />
<bean id="dog" class="com.java.Dog"/>

  • 在xml中显示装配
<!--在xml中显示装配 -->
<bean id="people" class="com.java.People">
    <property name="cat" ref="cat"/>
    <property name="dog" ref="dog"/>
</bean>

  • 在java中显示配置(此处未介绍)
  • 隐式的自动装配bean【重要】:有byName和byType两种装配形式
<!--autowire="byName" 会在容器上下文中查找,和自己对象set方法里的参数名称相同的beanid!-->
<bean id="people" class="com.java.People" autowire="byName" />

<!--autowire="byType"会自动在容器上下文中查找,和自己对象属性类型相同的bean,同一种类型需要全局唯一-->
<bean id="people" class="com.java.People" autowire="byType" />

小结:

  • byName时候,需要保证所有bean的id唯一,并且这个id需要和自动注入的属性的set方法的值一致!
  • byType时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!

使用注解实现自动装配

使用注解须知:

  1. 导入约束: contex约束
  2. 配置注解的支持: context:annotation-config/ 【重要!】
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

@Autowired注解

直接在属性上使用即可!也可以在set方法上使用

使用Autowired我们可以不用编写set方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且符合名字byname!

测试代码

public class People {
    @Autowired
    @Qualifier(value="cat")
    private Cat cat;
   	@Autowired
    private Dog dog;
    private String name;
}

如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用添加@Qualifier(value=“xxx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!

@Resource注解

测试代码

public class People {
    @Resource(name="cat")
    private Cat cat;
    @Resource
    private Dog dog;
    private String name;
}

小结:

@Autowired和@Resource的区别

  • 都是用来自动装配的,都可以放到属性字段上
  • @Autowired通过byType的方式实现【常用】
  • @Resource默认通过byName的方式实现,如果找不到名字,则通过byType实现【常用】

Spring注解开发

开启注解支持

<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.java" />
<context:annotation-config/>

@Component注解

@Component
public class User {
    public String name;
    
    //相当于<property name="name" value="tantu" />
    @value("tantu")
    public void setName(String name)
    {
        this.name = name;
    }
}

衍生的注解

@Component 有几个衍生注解,在web开发中,会按照mvc三层架构分层!

  • dao 【@Repository】
  • service 【@Service】
  • controller 【@Controller】

这四个注解的功能都是一样的,都是代表将某个类注册到Spring中,装配Bean

小结

xml与注解:

  • xml更加万能,适用于任何场合!维护简单方便
  • 注解 不是自己类使用不了,维护相对复杂!

xml和注解最佳实践

  • xml用来管理bean
  • 注解只负责完成属性的注入
  • 使用过程中需要注意一个问题:必须让注解生效,开启注解的支持(见上面)

代理模式

代理模式的好处:

  • 可以使得真实角色的操作更加纯粹,不用去关注一些公共的业务
  • 公共业务交给了代理角色,实现了业务的分工
  • 公共业务发生扩展的时候,方便集中管理

缺点:一个真实角色就会产生一个代理角色,代码量会翻倍,开发效率降低

AOP

请添加图片描述

AOP实现机制

动态代理

public class ProxyInvocationHandler implements InvocationHandler {
    
    //被代理的接口
    private Object target;
    public void setTarget(Object target) {
        this.target = target;
    }
    
    //生成得到代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), 								target.getClass().getInterfaces(), this);
    }
    
    //处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Objcet[] args) throws Throwable {
        //动态代理的本质,就是使用反射机制实现!
        Object result = method.invoke(target, args);
        return result;
    }
}
public static void main(String[] args) {
    //真实角色
    UserServiceImpl userService = new UserServiceImpl();
    //代理角色
    ProxyInvocationHandler pih = new ProxyInvocationHandler();
    //设置要代理的对象
    pih.setTarget(userService);
    //动态生成代理类
    UserService proxy = (UserService)pih.getProxy();
    
    proxy.func();//调用代理类的实际方法
}

需要了解两个类:Proxy:代理 InvocationHandler:调用处理程序

动态代理的好处:

  • 可以使得真实角色的操作更加纯粹,不用去关注一些公共的业务
  • 公共业务交给了代理角色,实现了业务的分工
  • 公共业务发生扩展的时候,方便集中管理
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值