0%

Java基础

“条条大路通罗马”原话是“All Roads Lead to Rome”,出自《罗马典故》,是指做成一件事的方法不只一种,人生的路也不止一条等着我们发现。

Java数据类型

一、基础

二、分类

  1. 基本数据类型

    • 整型:byte、short、int、long,如35,默认什么也不加就是int型,35B表示是byte型,35S表示short型,35L表示long型的
    • 浮点型:float、double,默认double,如要用float则应加”F”()
    • 字符型:char
    • 布尔型:boolean
  2. 引用数据类型

①String不是基本数据类型,是引用数据类型,它是java提供的一个类

②Java基本类型存储在栈中,因此它们的存取速度要快于存储在堆中的对应包装类的实例对象。从Java5.0(1.5)开始,JAVA虚拟机(Java Virtual Machine)可以完成基本类型和它们对应包装类之间的自动转换。因此我们在赋值、参数传递以及数学运算的时候像使用基本类型一样使用它们的包装类,但这并不意味着你可以通过基本类型调用它们的包装类才具有的方法。另外,所有基本类型的包装类都使用了final修饰,因此我们无法继承它们扩展新的类,也无法重写它们的任何方法。

③基本类型的优势:数据存储相对简单,运算效率比较高

包装类的优势:有的容易,比如集合的元素必须是对象类型,满足了java一切皆是对象的思想。

三、参考


Java构造函数

一、基础

      java构造函数,也叫构造方法,是java中一种特殊的函数。函数名与类名相同,无返回值,一般用来初始化成员属性和成员方法的,即new对象产生后,就调用了对象了属性和方法,在对象创建时即被调用。

特点

  1. 函数名与类名相同
  2. 不用定义返回值类型
    • 不同于void类型返回值,void是没有具体返回值类型
    • 构造函数是连类型都没有
  3. 不可以写return语句
    • 返回值类型都没有,故不需要return语句
  4. 一个类可以有多个构造函数
  5. 一般函数不能调用构造函数,只有构造函数才能调用构造函数

二、使用

三、参考

  1. 参考一

Java包

一、概念

      在编写Java程序时,随着程序架构越来越大,类的个数也越来越多,这时就会发现管理程序中维护类名称也是一件很麻烦的事,尤其是一些同名问题的发生。另一方面,有时开发人员还可能需要将处理同一方面的问题的类放在同一个目录下,以便于管理。基于以上原因,Java引入了包(package)机制,提供了类的多层命名空间,用于解决类的命名冲突、类文件管理等问题。

      Java使用包(package)这种机制是为了防止命名冲突,同时可以进行访问控制,提供搜索和定位类、接口、枚举和注释等。

  1. 语法package {package_name}

    • 包声明应该在源文件的第一行(无import关键字的情况)且每个源文件只能有一个包声明
      • 如果一个源文件中没有使用包声明,那么其中的类、函数、枚举、注释等将被放在一个无名的包(unnamed package)中。
  2. 包的3个作用如下:

    • 区分相同名称的类从而避免命名冲去。
    • 能够较好地管理大量的类,方便维护和查找。
    • 控制访问范围,拥有包访问权限的类才能访问某个包中的类。
  3. 特性

    • 如果Java文件中使用了package,那么该Java文件必须放在命名与package名称相同的目录下。
    • 包名全部由小写字母,多个单词也全部小写,如mypack1.mypack2.mypack3
    • 如果包名包含多个层次,每个层次用“.”分割,java解释器会将package中的.解释为目录分隔符/,如上面的例子:mypack1/mypack2/mypack3
    • 包名一般由倒置的域名开头,比如com.baidu(不要有www)。
    • 自定义包不能java开头。
    • 在同一package中的类是可以互相访问的,即不需要import即可使用

Java中的importC/C++中的#include是不同的,import并不会在当前java文件中嵌入另一个package中的类的代码,只是告诉java文件不属于该包的类能够到哪里去寻找而已,classpath是java在编译程序时查找类文件的路径,java编译器会在classpath中包含有的路径中查找java的类文件。

  1. import关键字
    • import语句并不是必需的,如果在类里使用其它类的全名可以不使用import语句
    • 导入包中的全部类:import 包名.*;
      • 使用星号*会增加编译时间,特别是引入多个大包时,所以一般使用时会指定某个具体的类
    • 导入包中的某个具体类:import 包名.类名;

Java默认为所有源文件导入java.lang包下的所有类,因此前面在Java程序中使用StringSystem类时都无须使用import语句来导入这些类。

二、使用

TODO

三、参考

  1. 参考一
  2. 参考二
  3. 参考三

Java注解

一、概念

      Java注解(Annotation)又称Java标注,是JDK5.0引入的一种注释机制。Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java虚拟机可以保留标注内容,在运行时可以获取到标注内容。当然它也支持自定义Java标注。

  1. 分类

    • 按照运行机制:
      • 源码注解:只存在.java文件中,编译时就不存在了(平时对代码的逻辑说明等)
      • 编译时注解:注解在源码和.class文件如:@Override``@Suppvisewarnings等,他们只在编译时起作用,按照注解的指定来编译
      • 运行时注解:在运行时期作用,如Spring中@Autowired在运行时会把对应的Bean注入到指定属性中。
    • 按照来源:
      • 来自JDK的注解
      • 来自第三方的注解
      • 自定义注解
    • 元注解:注解的注解
      • @Target:标志注解可以在那些地方可以使用。
      • @Retention:描述注解的生命周期,表示需要在什么级别保存该注解,即保留的时间长短。
      • @Documented:描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。
        • 它是一个标记注解,没有成员。
      • @Inherited:只能被用来标注“Annotation类型”,表示它所标注的Annotation具有继承性。
      • @Repeatable:Java 8新增,允许在相同的程序元素中重复注解。
      • @Native:Java 8新增,修饰成员变量,表示这个变量可以被本地代码引用,常常被代码生成工具使用。
  2. 作用

    • 编译检查,常见如:

      • @Override:告诉编译器这个方法是一个重写方法,如果父类中不存在该方法编译器便会报错,提示该方法没有重写父类中的方法,这样可以防止不小心拼写错误造成麻烦。

        • 只能标注方法
      • @Deprecated:所标注内容不再被建议使用,如果使用或者进行重写,程序会发出警告。

        • 一般某个类不再使用会加上此注解,如功能设计的时候某个类存在,实际开发过程中该类没有被使用同时又不保证后期会不会再重新使用就可以使用此注解
      • @SuppressWarnings:告诉编译器对被批注的代码元素内部的某些警告保持静默。

        关键字 作用
        all 抑制所有警告
        boxing 抑制装箱、拆箱操作时候的警告
        cast 抑制映射相关的警告
        dep-ann 抑制启用注释的警告
        deprecation 抑制过期方法警告
        fallthrough 抑制确在switch中缺失breaks的警告
        finally 抑制finally模块没有返回的警告
        hiding 不常用
        incomplete-switch 忽略没有完整的switch语句
        nls 忽略非nls格式的字符
        null 忽略对null的操作
        rawtypes 使用generics时忽略没有指定相应的类型
        restriction 不常用
        serial 忽略在serializable类中没有声明serialVersionUID变量
        static-access 抑制不正确的静态访问方式警告
        synthetic-access 抑制子类没有按最优方法访问内部类的警告
        unchecked 抑制没有进行类型检查操作的警告
        unqualified-field-access 抑制没有权限访问的域的警告
        unused 抑制没被使用过的代码的警告
    • 生成帮助文档,如@Documented

    • 在反射中使用Annotation

    • 便于查看和维护代码,如@Override可以清楚的知道这是一个重写方法

    • 在框架中使用,简化程序配置

二、使用

TODO

三、参考

  1. 参考一
  2. 参考二

Java泛型

一、概念

      泛型程序设计(generic programming)是程序设计语言的一种风格或范式。泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型。

Java泛型(generics)是JDK5中引入的一个新特性,泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型(只在编译阶段有效)。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

      在Java早期使用Object类型来接收任意的对象类型,但是在实际的使用中会有类型转换的问题,即:向上转型没有任何问题,但是向下转型时其实隐含了类型转换的问题,这就是程序不安全的原因。也就是因为存在这种安全隐患,所以Java在JDK5以后就提供了泛型来解决这个安全问题。

分类:

泛型类

泛型方法

泛型接口

泛型通配符

二、使用

假定目录为/Users/java

  1. 泛型类:泛型类型用于类的定义中,通过泛型可以完成对一组类的操作对外开放相同的接口。
    • 泛型的类型参数只能是类类型,不能是简单类型。
    • 不能对确切的泛型类型使用instanceof操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#Generic.java
public class Generic<T>{
private T key;

public Generic(T key) {
this.key = key;
}

public T getKey(){
return key;
}
}

#MainClass.java
public class MainClass {
public static void main(String[] args) {
Generic<Integer> genericInteger = new Generic<Integer>(123456);
Generic<String> genericString = new Generic<String>("abc");

System.out.println("key的值:" + genericInteger.getKey());
System.out.println("key的值:" + genericString.getKey());

System.out.printf("key的值:%d\n", genericInteger.getKey());
System.out.printf("key的值:%s\n", genericString.getKey());
}
}

  1. 泛型方法

  2. 泛型接口

  3. 泛型通配符

三、参考

  1. 参考一
  2. 参考二

Java反射

一、概念

      反射(Reflection)是Java的特征之一,它允许运行中的Java程序获取自身的信息,并且可以操作类或对象的内部属性。

      在Java里有一句话:万物皆对象,而一个对象必然有一个与之对应的类。具体到代码层面,Java中每个类都有一个与之对应的类对象(Class对象),这个类对象由JVM生成并保存了对应类的相关信息,而类对象所对应的类就是java.lang.Class,它是所有反射API的入口点。

获取Class类对象的三种方法

  • 使用Class.forName静态方法,如Class clz = Class.forName("java.lang.String");
  • 使用.class方法,如Class clz = String.class;
  • 使用类对象的getClass()方法,如String str = new String("Hello"); Class clz = str.getClass();

反射的用法

  1. 通过反射创建类对象,分为两种:

    • 通过Class对象的newInstance()方法
    • 通过Constructor对象的newInstance()方法
  2. 通过反射获取类属性、方法、构造器

    • 获取属性
      • getFields()获取类中所有被public修饰的所有属性
      • getDeclaredFields()获取类中所有的属性(不包括继承下来的属性)
    • 获取方法
      • getMethods()获取类中被public修饰的所有方法(包括从父类中继承的那一部分)
      • getDeclaredMethods()获取所有方法(不包括从父类中继承的那一部分)
    • 获取构造器
      • getConstructors()获取类中所有被public修饰的构造器
      • getDeclaredConstructors()获取类中所有构造器
  3. 通过反射调用方法

    • 通过反射获取到某个Method类对象后可以通过调用invoke方法执行invoke(Oject obj, Object... args)
  4. 通过反射设置访问属性setAccessible(bool)

  5. 通过反射获取注解

    • getAnnotations()获取该对象上的所有注解
    • getDeclaredAnnotations()获取该对象上的显式标注的所有注解(不包括继承下来的注解)

应用场景

  • 框架开发
  • 工厂模式,消除多个分支
  • 动态加载类

二、使用

  1. 简单例子

    • code

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      >>>reflect/Fruit.java

      package reflect;

      class Fruit {
      public String name;
      protected int num;
      private int price;

      public Fruit(String name, int price) {
      this.name = name;
      this.price = price;
      }

      public int getPrice() {
      return price;
      }

      public void setPrice(int price) {
      this.price = price;
      }
      }

      >>>reflect/FruitMain.java

      package reflect;

      import java.lang.reflect.*;

      class FruitMain {
      // @SuppressWarnings("rawtypes")
      public static void main(String[] args) {
      // 正常的调用
      Fruit apple = new Fruit("Apple", 15);
      System.out.println("Apple Init Price:" + apple.getPrice());
      apple.setPrice(5);
      System.out.println("Apple Set Price:" + apple.getPrice());

      try {
      // 使用反射调用
      Class<?> clz = Class.forName("reflect.Fruit");
      Constructor<?> con = clz.getConstructor(String.class, int.class);
      Method getPriceMethod = clz.getMethod("getPrice");
      Fruit pearObj = (Fruit)con.newInstance("Pear", 10);
      System.out.println("Pear Init Price:" + getPriceMethod.invoke(pearObj));
      Method setPriceMethod = clz.getMethod("setPrice", int.class);
      setPriceMethod.invoke(pearObj, 14);
      System.out.println("Pear Set Price:" + getPriceMethod.invoke(pearObj));
      } catch (ClassNotFoundException e) {
      e.printStackTrace();
      } catch (InstantiationException e) {
      e.printStackTrace();
      } catch (IllegalAccessException e) {
      e.printStackTrace();
      } catch (Exception e) {
      e.printStackTrace();
      }

      try {
      // 使用反射调用
      Class<?> clz = Class.forName("reflect.Fruit");
      Method method = clz.getMethod("setPrice", int.class);
      Method method1 = clz.getMethod("getPrice");
      Class<?>[] parTypes = new Class<?>[2];
      parTypes[0] = String.class;
      parTypes[1] = int.class;
      Constructor<?> con = clz.getConstructor(parTypes);
      Object[] pars = new Object[2];
      pars[0] = "Banana";
      pars[1] = 11;
      Object obj = con.newInstance(pars);
      System.out.println("Banana Init Price:" + method1.invoke(obj));
      method.invoke(obj, 8);
      System.out.println("Banana Set Price:" + method1.invoke(obj));
      } catch (Exception e) {
      e.printStackTrace();
      }

      }
      }
    • javac reflect/Main.java

    • java reflect.Main

      1
      2
      3
      4
      5
      6
      Apple Init Price:15
      Apple Set Price:5
      Pear Init Price:10
      Pear Set Price:14
      Banana Init Price:11
      Banana Set Price:8

三、参考

  1. 参考一
  2. 参考二
  3. 参考三
  4. 参考四
  5. 参考五
  6. 参考六
  7. 参考七
  8. 参考八

Java三大器

  1. 过滤器
  2. 拦截器
  3. 监听器

Java四大域

  1. ServletContext域
  2. Request域
  3. Session域
  4. PageContext域

Java九大隐式对象

jsp被翻译成servlet之后,service方法中有9个对象定义并初始化完毕,在jsp脚本中可以直接使用这9个对象。

  1. page
  2. confing
  3. application
  4. response
  5. request
  6. session
  7. out
  8. exception
  9. pageContext

Tomcat

  1. Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。对于一个初学者来说,可以这样认为,当在一台机器上配置好Apache服务器,可利用它响应HTML(标准通用标记语言下的一个应用)页面的访问请求。实际上Tomcat是Apache 服务器的扩展,但运行时它是独立运行的,所以当你运行tomcat 时,它实际上作为一个与Apache 独立的进程单独运行的。

  2. 安装

    • 安装[Tomcat]https://tomcat.apache.org/download-90.cgi)
      • cd /usr/local/src/ && sudo wget http://ftp.cuhk.edu.hk/pub/packages/apache.org/tomcat/tomcat-9/v9.0.34/bin/apache-tomcat-9.0.34.tar.gz
    • cd /usr/local && sudo tar -zxvf apache-tomcat-9.0.34.tar.gz
  3. 参考


Maven

  1. Maven是一个项目管理工具,它包含了一个项目对象模型(Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),以及用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。

    • maven是java的包管理工具,相当于是nodejs中的npm,php中的composer,python中的pip等,通过maven可以方便地引入各种java的第三方类库(包括Spring、Struts、junit等)和插件(如tomcat等)。
  2. 安装

    • 安装Java SE,直接选择了dmg安装

      • 默认安装目录/Library/Java/
    • 安装Maven

      • brew安装brew install maven

      • 源码安装

        • cd /usr/local/src
        • wget http://apache.communilink.net/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz
        • 解压
          • cd /usr/local
          • sudo tar -zxvf apache-maven-3.6.3-bin.tar.gz
        • 设置环境变量vim ~/.bash_profile,加入maven的bin路径
        • source ~/.bash_profile立即生效
        • 查看安装是否成功mvn -v
        1
        2
        3
        4
        5
        Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
        Maven home: /usr/local/apache-maven-3.6.3
        Java version: 14, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-14.jdk/Contents/Home
        Default locale: zh_CN_#Hans, platform encoding: UTF-8
        OS name: "mac os x", version: "10.15.5", arch: "x86_64", family: "mac"
  3. 使用mvn -h

    • 常用命令
      • 创建maven项目:mvn archetype:create
        • 指定group-DgroupId=packageName
        • 指定artifact-DartifactId=projectName
        • 创建web项目:-DarchetypeArtifactId=maven-archetype-webapp
      • 创建maven项目:mvn archetype:generate
      • 验证项目是否正确:mvn validate
      • maven打包:mvn package
      • 只打jar包:mvn jar:jar
      • 生成源码jar包:mvn source:jar
      • 产生应用需要的任何额外的源代码:mvn generate-sources
      • 编译源代码:mvn compile
      • 编译测试代码:mvn test-compile
      • 运行测试:mvn test
      • 运行检查:mvn verify
      • 清理maven项目:mvn clean
      • 生成eclipse项目:mvn eclipse:eclipse
      • 清理eclipse配置:mvn eclipse:clean
      • 生成idea项目:mvn idea:idea
      • 安装项目到本地仓库:mvn install
      • 发布项目到远程仓库:mvn:deploy
      • 在集成测试可以运行的环境中处理和发布包:mvn integration-test
      • 显示maven依赖树:mvn dependency:tree
      • 显示maven依赖列表:mvn dependency:list
      • 下载依赖包的源码:mvn dependency:sources
      • 安装本地jar到本地仓库:mvn install:install-file -DgroupId=packageName -DartifactId=projectName -Dversion=version -Dpackaging=jar -Dfile=path
    • web项目相关命令
      • 启动tomcat:mvn tomcat:run
      • 启动jetty:mvn jetty:run
      • 运行打包部署:mvn tomcat:deploy
      • 撤销部署:mvn tomcat:undeploy
      • 启动web应用:mvn tomcat:start
      • 停止web应用:mvn tomcat:stop
      • 重新部署:mvn tomcat:redeploy
      • 部署展开的war文件:mvn war:exploded tomcat:exploded
    • 其他
      • mvn clean:表示运行清理操作(会默认把target文件夹中的数据清理)。
      • mvn clean test:运行清理和测试。
      • mvn clean compile:表示先运行清理之后运行编译,会将代码编译到target文件夹中。
      • mvn clean package:运行清理和打包。
      • mvn clean install:运行清理和安装,会将打好的包安装到本地仓库中,以便其他的项目可以调用。
      • mvn clean deploy:运行清理和发布(发布到私服上面)。

Netty

  1. Netty是由JBOSS提供的一个java开源框架,现为 Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。也就是说,Netty 是一个基于NIO的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCP和UDP的socket服务开发。
    • 简单来说有了Netty你可以实现自己的HTTP服务器,FTP服务器,UDP服务器,RPC服务器,WebSocket服务器,Redis的Proxy服务器,MySQL的Proxy服务器等。

Spring

  1. spring 是一个开源框架,处于mvc的控制层,能应对需求的快速变化,主要原因是它有一种面向切面编程(aop)的优势,其次它提升了系统性能,是因为通过依赖倒置机制(ioc),系统中用到的对象不是在系统加载时就全部实例化,而是在调用到这个类时才会实例化该对象。

    • 轻量:从大小到开销来说都是轻量的,spring框架开源字啊一个只有1m大小的jar文件中发布,而且spring所处理的开销也是微不足道的
    • 非侵入式:spring应用中的对象不依赖于spring的特定类
    • IOC(控制反转):一个对象依赖的其他对象会通过被动的方式传递进来,而不是这个对象自己创建或者主动查找依赖对象
    • AOP(面向切面):只完成业务逻辑,并不负责其他的系统级的关注点,有两种实现方式:
      • jdk动态代理
      • CGLib动态代理
    • 容器:定义了bean是如何创建、配置、管理的
    • 框架模块:可以不必将应用完全基于spring,可以自由的挑选适用你的模块,而忽略其余的模块
    • 核心容器:提供了依赖注入特征来实现容器对bean的管理。这里最基本的概念是BeanFactory,它是任何spring应用的核心。BeanFactory是工厂模式的一个实现,他使用ioc将应用配置和依赖说明从实际的应用代码中分离出来
    • 应用上下文(context)模块:核心模块的beanFactory使spring成为了一个容器,而上下文模块使他成为一个框架,这个模块扩展了BeanFactory的概念,增加了对国际化消息、事件传播以及验证的支持。
  2. spring bean加载、注入过程

    • 执行该对象的构造方法
    • 执行set参数注入方法
    • 执行BeanNameAware的实现方法获取bean的id
    • 执行BeanFactoryAware的实现方法获取bean的工厂
    • 执行BeanPostProcessor的postProcessBeforeInitalization处理方法
    • 执行In
  3. spring事务的传播机制有以下几种:

    • PROPAGATION_REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
    • PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
    • PROPAGATION_MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
    • PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
    • PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
    • PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
    • PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。
  4. springboot核心配置文件

    • applicaion:主要用于springboot项目的自动化配置
    • boostrap:主要用于一些固定的不能被覆盖的属性,一些加密解密的场景。

      配置文件有properties和yml格式,其中yml格式不支持@propertySource注解导入配置。

  5. springboot核心注解:启动类上面的注解是@springbootApplication,它是核心注解,包含了以下三个注解

    • @springbootConfiguration:组合了@Configuration注解,实现配置文件的功能
    • @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项
    • @ComponentScan:spring组件扫描
  6. 开启springboot特性的几种方式:

    • 继承spring-boot-starter-parent项目
    • 导入spring-boot-dependencies项目依赖
  7. springboot 配置加载顺序

    • properties
    • yaml文件
    • 系统环境变量
    • 命令行参数

Java九大隐式对象