所谓的泛型就是在类定义时,不为类中属性和方法指定数据类型,而是在类对象创建时为其指定相应的数据类型。
其实我们再使用集合时就用过泛型List
创建一个List对象List list=new ArrayList();
它就是泛型。
解决数据类型的安全问题
泛型的主要目标是提高 Java 程序的类型安全。编译时的强类型检查;通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。其主要原理是在类声明时通过一个标识表示类中某个属性的数据类型或者是某个方法的返回值及参数类型。这样在类声明或者实例化时只要指定好需要的类型即可。
泛型可以定义在类上,接口上,方法上。 泛型类,泛型接口以及泛型方法。
泛型定义的格式:
修饰符 class 类名 <泛型标志,泛型标志.......>{
}
//这是使用的是默认修饰符
//T标志可以任意起名。
class Point{
//定义T类型的对象
private T name;
//普通方法
public void show(){
System.out.println("name的名字是:"+name);
}
public T getName() {
return name;
}
public void setName(T name) {
this.name = name;
}
public Point() {
}
public Point(T name) {
this.name = name;
}
}
//新建测试类调用定义好的泛型类(调用时可以指定泛型的类型,默认为Object类型)
public class Test02 {
public static void main(String[] args) {
//指定泛型为字符串类型
Point point = new Point();
point.setName("st");
point.show();
//指定泛型为Integer类型(可以通过get、set传参,也可以直接使用构造函数传参)
Point point = new Point(53);
point.show();
//指定泛型为Double类型
Point point = new Point(5.3);
point.show();
}
}
注意: 上面的泛型类型必须都是引用类型。不能是基本类型
在开发中对象的引用传递是最常见的,但是如果在泛型类的操作中,在进行引用传递时泛型类型必须匹配才可以传递,否则是无法传递的。如果想传递,可以定义泛型为?通配符。
public class Demo02 {
public static void main(String[] args) {
//不定义则是Object类型
Info info = new Info();
info.setT("3.23sdkd");
fun(info);
//定义泛型为String类型
Info info1 = new Info<>();
//只能添加String类型的值
info1.setT("哈哈哈");
//fun(info1);
//定义泛型为Inter类型
Info info2 = new Info();
info2.setT(34);
fun(info2);
}
//使用通配符使该参数的泛型可以接受任意的类型
public static void fun(Info> info){
info.show();
}
}
//泛型类
class Info{
private T t;
public void show(){
System.out.println("输出T:"+t);
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public Info() {
}
public Info(T t) {
this.t = t;
}
}
在引用传递中,在泛型操作中也可以设置一个泛型对象的范围上限和范围下限。范围上限使用extends关键字声明,表示参数化的类型可能是所指定的类型或者是此类型的子类,而范围下限使用super进行声明,表示参数化的类型可能是所指定的类型或者此类型的父类型。
语法:
[设置上限]
声明对象: 类名称 extends 类> 对象名称;
定义类: [访问权限] 类名称<泛型标识 extends 类>{}[设置下限]
声明对象: 类名称 super 类> 对象名称;
定义类: [访问权限] 类名称<泛型标识 super 类>{}
public class Demo02 {
public static void main(String[] args) {
//泛型上限
//该类定义上限为Number,set值和构造函数添加值都只能添加Number类型的值或其子对象,Object(其他类型)类型会报错
People people = new People();
people.setE(542);
sx(people);
//泛型下限(若引用类时不定义泛型,则无论谁引用时下限皆为类的下限)
Info info3 = new Info<>();
info3.setT(2.33);
xx(info3);
}
//指定泛型上限(若调用的类对象定义了泛型下限,则泛型下限按调用的类对象的下限计算)
public static void sx(People extends Number > people){
peopl.show();
}
//(若调用的类对象定义了泛型下限,则泛型下限按定义的类的下限计算,调用时再定义则不起作用)
public static void xx(Info super Double> info){
info.show();
}
}
class Peopl{
private E e;
public E getE() {
return e;
}
public void setE(E e) {
this.e = e;
}
public Peopl() {
}
public Peopl(E e) {
this.e = e;
}
public void sho(){
System.out.println("输出E:"+e);
}
}
上面的例子都是使用泛型类。而在jdk1.5以后,泛型也可以定义在接口上了,定义接口的泛型和定义泛型类语法相似。
语法:
public interface 接口名<泛型标志,泛型标志....>{
//静态常量
//抽象方法。
}
泛型接口的定义
//泛型接口
interface USB{
//定义常量(常量的命名必须全部大写)
public static final String NAME = "";
//定义抽象方法
T fun();
}
调用泛型接口
//子类在实现接口时,确定泛型类型
class Uupark implements USB{
@Override
public String fun() {
return "1234";
}
}
//子类若定义泛型必须包含和接口类相同的泛型
class Upan implements USB{
@Override
public T fun() {
return null;
}
}
前面的所有泛型操作都是将整个类进行泛型化,但同样也可以在类中定义泛型化的方法。泛型方法的定义与其所在的类是否是泛型类是没有任何关系的,所在的类可以是泛型类,也可以不是泛型类。
泛型方法的简单定义:
[访问权限] ==<泛型标识>== 泛型标识 方法名称(泛型标识 参数名称)
class Span{
private String a;
//类无泛型时定义泛型方法
//泛型方法: static静态成员,随着类的加载而被加载到JVM内存中。常量池
public static T show(T t){
return t;
}
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public Span() {
}
public Span(String a) {
this.a = a;
}
}
class Tescher{
private T t;
//类有泛型时定义泛型方法
public E ff(E e){
return e;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public Tescher() {
}
public Tescher(T t) {
this.t = t;
}
}
//泛型方法的使用
public class Demo05 {
public static void main(String[] args) {
Span span = new Span();
String dfd = span.show("dfd");
System.out.println(dfd);
Tescher tescher = new Tescher<>();
Double ff = tescher.ff(2.32);
System.out.println(ff);
}
}
java注解是在JDK5的时候引入的一种新特性。
注解(也可以称为元数据)为在代码中添加信息提供了一种形式化的方法,使得在代码中任一时刻可以非常方便的使用这些数据。
注解类型定义了一种新的特殊接口类型,在接口关键期interface之前加@符号,即用@interface即可区分注解与普通接口声明。目前大部分框架都是通过使用注解简化代码提高编码效率注解类型于注释:
注释: java不会编译注释的内容,注释给程序员看的。
注解: 它是程序看,当程序看到这个注解时,就应该解析它。
譬如: @Controller @Override
- 提供信息给编译器:编译器可直接通过注解探测错误和警告信息,例如:@Override,@Deprecated
- 编译阶段时的处理:软件工具可以用来利用注解信息生成代码、html文档或者做其他相应处理,例如:@Param,@Return,@See,@Author用于生成javadoc文档
- 运行时的处理:某些注解可以在程序运行时接收代码的提取,但注解本身不是代码的一部分
1. @Override: 重写得注解。符合重写得规则。
2. @Deprecated: 表示已过时。
3. @SuppressWarnings: 表示压制警告。
4. @FunctionInterface: 表示函数式接口。表示该接口中有且仅有一个抽象方法。
语法:
public @interface 注解名{
//注解属性
}
定义注解
//自定义注解
@interface User{
//注解属性
}
//使用注解
@User
class Info{
@User
public String name;
@User
public void show(){
System.out.println("show================="+name);
}
}
ps:使用注解和不使用注解没有区别?
注解本身没有任何意义,它只有被解析了,才会赋予真正的意义。
我们后会使用反射来对象注解进行解析。
像:@Override 它被JVM解析,从而使其具有相应的意义。
@Controller @RequestMapping 它被Spring框架解析,所以具有相应的意义。
定义在注解上的注解称为元注解。
@Controller它只能加在类上 @Override它只能加在方法上。
原因是它使用了元注解可以设置注解使用的位置。
1. @Target(value=可以取下面这些内容): 作用限制注解使用得位置。
/** 表示可以作用在类,接口,枚举 */
TYPE,/** 属性 */
FIELD,/** 普通方法上 */
METHOD,/** 方法参数 */
PARAMETER,/** 构造方法上 */
CONSTRUCTOR,/** 局部变量 */
LOCAL_VARIABLE2. @Retention: 注解什么时候生效。默认时源码 java经历了那些阶段。
源码阶段-->字节码阶段--->运行阶段
/**
* 源码时生效
*/
SOURCE,/**
* 字节码时生效
*/
CLASS,/**
* 运行时生效。
* 在JVM内存中还有该注解。
都会被设置为运行时有效
*/
RUNTIME
3. @Documented 当生产API文档时该注解还存在。4. @Inherited 是否运行被子类继承。
@User
public class Demo01 {
public static void main(String[] args) {
My my = new My();
my.name = "跌倒爬起";
my.show();
//引用枚举类型
mj name = mj.NAME;
System.out.println(name);
System.out.println(mj.AGE);
System.out.println(mj.ADDRESS);
}
}
//自定义注解
//指定哪里能出现注解
@Target(value = {ElementType.TYPE,ElementType.METHOD})
//什么情况下显示注解(SOURCE 源码显示注解,CLASS .class文件中和源码都显示,RUNTIME .class、源码和反射都能显示)
@Retention(value = RetentionPolicy.RUNTIME)
//生成api文档时存在注解
@Documented
//子类继承时是否继承该注解
@Inherited
@interface User{
}
@User
class My{
public String name;
@User
public void show(){
System.out.println("name的值:"+name);
}
}
//因为存在@Inherited父类的注解存在该属性,所以子类也会继承该注解
class Childs extends My{
}
enum mj{
NAME,AGE,ADDRESS
}
6.自定义注解---高级
@RequestMapping("/hello") 具有hello属性,但我们定义的却没有,因为它定义@RequestMaping注解中有属性。
语法:
@interface 注解名{
数据类型 属性名() default 默认值;
}数据类型: 基本类型,字符串类型,枚举类型【常量】,注解类型,数组类型【必须是上面这些类型的数组】
//自定义注解
//指定哪里能出现注解
@Target(value = {ElementType.TYPE,ElementType.METHOD})
//什么情况下显示注解(SOURCE 源码显示注解,CLASS .class文件中和源码都显示,RUNTIME .class、源码和反射都能显示)
@Retention(value = RetentionPolicy.RUNTIME)
//生成api文档时存在注解
@Documented
//子类继承时是否继承该注解
@Inherited
@interface User{
String value();
String[] ss() default {};
int age() default 15;
}
@User(value = "hh",ss = "嵇康")
class My{
public String name;
@User(value = "hh",age = 15)
public void show(){
System.out.println("name的值:"+name);
}
}