Static的认识及应用
stati修饰成员变量
public class Student{ static String name;//有static修饰,属于类,与类一起加载,在计算机里只有一份,会被类的全部对象共享 int age;//无static修饰,属于对象,每个对象都有一份 } static: 叫静态,可以修饰成员变量和成员方法 static修饰的成员变量叫做类变量
无static修饰叫做实例变量,就是平常使用的对象的变量
访问类变量 //类名.类变量(推荐) //对象.类变量(不推荐)
访问实例变量:
//对象.实例变量
Student s1=new Student(); s1.number="100"; Student.name="李华"; s1.name="李华"; Student s2=new Student(); s2.name="华立"; System.out.println(s1.name);// 华立 System.out.println(s2.name);//华立 System.out.println(Student.name);//华立 // 三种方式引出来的name变量全都是华立而不是李华,证明类变量是唯一存在的,而不是对象创建一个他就创建一个
//实例变量的用法 System.out.println(s1.number = "223");//223 System.out.println(s2.number = "233");//233 //Student.number="332"; 实例变量不能这样访问,会报错,不能清楚的表明是哪个学生对象的age
类变量应用:在开发中,如果某个数据只有一份且希望能够被共享(访问,修改),则该数据可以定义成类变量来记住
案例:系统启动后要求用户记住自己创建了多少用户对象
static修饰的成员方法
static修饰的成员方法称为类方法,也叫静态方法,属于类
访问类方法:
1.类名.类方法(推荐)
2.对象名.类方法(不推荐)
1.不能在类方法中访问实例变量和实例方法而在实例方法中可以访问类方法和类变量和实例变量和实例方法
2.类方法中不能出现this关键字,而实例方法中可以使用this关键字
package Static_Attention; public class Student { static String schoolname; double scores;//实例变量 public static void printHelloWorld(){ schoolname="黑马"; printHelloWorld2(); printHelloWorld(); // System.out.println(scores); 不能在类方法中访问实例变量 // printpass();报错 } public static void printHelloWorld2(){ } // 实例方法中既可以直接访问类成员也可以直接访问实例成员 public void printpass(){//实例方法 schoolname="黑马"; printHelloWorld2(); printHelloWorld(); System.out.println(scores); printpass(); } }
main方法也是类方法,当我们用Java去执行程序时,虚拟机会直接用类名.来调出main方法
public static void main(String[] args) { }
其中,String[] args是main方法的参数,
在cmd编译时可以在将其加工成为class文件后输入
java HelloWorld 12 13 45
那么,12,13,45便是参数
类方法可以做工具类
1.可以提高代码的复用性,
2.调用方便
3.提高开发效率
4.不用实例方法做工具类的原因:实例方法需要创建对象来调用,此时对象只为调用方法,对象占内存,会浪费内存
例如:
public class loginDemo1 { public static void main(String[] args) { //生成四位数验证码 Myutil.creatcode(4);再次行访问类方法,这种需要和类方法在同一个包下,否则需要导包 } }完成以上要求编辑以下工具类
import java.util.Random; public class Myutil { private Myutil(){ // 工具类没必要创建对象,建议将工具类进行私有 } public static String creatcode(int n){ String code=""; String data="abcdefghijklmonpqrstuvwxyzABCDEFGHIJKLMONPQRSTUVWXYZ0123456789"; Random sc=new Random(); for (int i = 0; i < n; i++) { int index=sc.nextInt(data.length()); code+=data.charAt(index); } System.out.println(code); return code; } }
代码块
根据代码块有无static修饰,分为静态代码块和实例代码块
1.静态代码块
格式:static{}
特点:类加载时自动执行,由于类只会加载一次,静态代码块也只会执行一次。
作用:加载优先级很高,可以完成类的初始化,例如对类变量的初始化赋值
2.动态代码块
格式:{}
特点:每次创建对象时执行实例代码块并在构造器之前执行
作用:和构造器一样,也是来完成类的初始化的,例如:对实例变量进行初始化赋值
public class Student { static int scores; int number; //静态代码块 static { System.out.println("静态代码块执行了"); scores=100; } //实例代码块 { System.out.println("实例代码块执行了"); number=500;//可以初始化,但没有意义,和创建实例变量是一样的,这个赋值会被构造器复制所覆盖 System.out.println("有人创建了对象,对象地址是"+this); //可以把许多构造器中的重复代码拿到实例代码块中写一次 } public Student() { } public Student(int number) { this.number = number; } }
单例模式
1.饿汉式单例
public class modation { // 设计模式即使具体问题的最优解决方案 //单例设计模式 //1.确保一个类只有一个对象 //2.写法: // (1)把类的构造器私有 //(2)定义一个类变量记住一个类的对象 //(3)定义一个类方法,返回对象 // 单例应用场景:任务管理器,获取运行时对象 //好处:可以避免浪费内存 public static void main(String[] args) { A a1=A.getobject(); A a2=A.getobject(); System.out.println(a1);//object.A@4554617c System.out.println(a2);//object.A@4554617c // 地址一样 // Runtime } }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public class A { private static A a=new A(); private A(){ } public static A getobject(){ return a; } }
2.懒汉式单例:
public class Test { //懒汉式单例设计模式 //写法 // 1.把构造器私有 //2.定义一个类变量用于储存对象 //3.提供一个类方法,保证返回的是同一个对象 public static void main(String[] args) { B b1=B.getInstance(); B b2=B.getInstance(); System.out.println(b1==b2); } // 如果单例对象经常用到就用饿汉式单例,反之用懒汉式单例 }
~~~~~~~~~~~~~~~~~~~~~~
public class B { private static B b; public static B getInstance(){ if (b==null){ new B(); } return b; } }
如果这个单例对象经常用到就用饿汉式单例,反之用懒汉式单例
单例模式确保了一个类只有一个对象
单例设计模式应用场景:
一种运行环境只需要一个对象就使用单例模式,例如任务管理器,避免浪费内存
面向对象:继承
继承概念:
Java提供了一种特殊的关键字,用这个关键字可以让一个类和另一个类建立起父子关系
//继承的入门 //继承指Java的一个特殊关键字extends //以此,可以让一个类和另一个类建立起父子关系 //例如下面的代码 /*public class B extends A{ }*/ //其中A类称为父类(基类或超类) //B类称为子类(派生类) //子类能继承父类非私有的成员 //子类的对象有子类和父类共同完成
public static void main(String[] args) { B b=new B();//可以访问父类子类两者开放的对象 System.out.println(b.i); //System.out.println(b.j);//报错//j' has private access in 'Oriented_Inherit.A' } }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~··
// 父类 public class A { //公开成员 public int i; public void print1(){ System.out.println("===print1==="); } //私有成员 private int j; private void print2(){ System.out.println("===print2==="); } }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~·
//子类 public class B extends A { public void print3(){ System.out.println(i); print1(); } }j继承可以减少重复代码的编写,提高了代码的复用性
权限修饰符:
1.修饰符用来限定类中的成员能够被访问的范围
2.修饰符范围:
修饰符 | 在本类中 | 在同一类的其他包下 | 在任意包的子类里 | 任意包下的任意类里 |
private | √ | |||
缺省 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
同一个类:
package 权限修饰符; public class fu { private void goal(){ System.out.println("===private==="); } void start(){ System.out.println("===缺省==="); } protected void maduls(){ System.out.println("===protected==="); } public void food(){ System.out.println("===public==="); } public void test1(){ goal(); start(); maduls(); food(); //同一个类中全部可以访问 } }同一个包:
package 权限修饰符; public class quanxian { //四种权限修饰符//public , private,protected,缺省(不写) //权限修饰符就是限制类中的成员能够被访问的范围 public static void main(String[] args) { fu sc=new fu(); //sc.goal();//报错//Cannot resolve method 'goal' in 'quanxian' sc.start(); sc.maduls(); sc.food(); } }任意包的子类:
package extend; import 权限修饰符.fu; public class zf extends fu { public void test(){ maduls(); food(); //goal();// 报错 //stars();//报错 } }
package extend; 任意包下的任意类里: import 权限修饰符.fu; public class zf2 { public static void main(String[] args) { fu f=new fu(); f.food(); //f.maduls();//error zf z=new zf(); z.food(); //z.maduls();//error,proteced可以被任意包的子类访问而不是被任意包的子类对象访问 } }
final修饰符(和static共称为状态修饰符)
称为最终态,可以修饰成员方法,成员变量,类,局部变量
//final可以使变量有且只能复制一次 //变量类型有: //一:局部变量 //二:成员变量 //1.静态成员变量 //2.实例成员变量 //final修饰基本类型变量,变量存储的数据不能被改变 //final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的 //上面这句话对于String来说,String存的是地址,但改变了字符串也就改变了地址,所以,字符串内容不能修改,数组可以通过只修改内容来修改 // 使用static final修饰的成员变量称为常量 // 通常用于记录系统的配置信息
常量:
*常量:public static final修饰的成员变量,建议名称全部大写,多的单词之间用下划线隔开,例如SCHOOL_NAME;
单继承:
java是单继承的,不支持多继承,但支持多层继承
例如B类可以继承A类,C类可以继承B类但C类不可以继承A类和B类(C extens A,C extens B)
在Java中,所有的所有的类都默认继承Object类例如上面的例子中,A类默认继承Object类,而B,C类简介成为Object类的子类
方法重写:
当子类觉得父类中的某个方法不好用,或者没办法满足需求,子类可以重写一个方法名称,参数列表一样的方法,去覆盖父类的方法这就是方法重写 方法重写后,java遵循就近原则,直接访问子类中重写的方法而不是父类中的方法
私有方法,静态方法不能被重写
静态方法不能进行方法重写是因为静态方法是属于类的方法,而不是属于对象的方法。在Java中,方法重写是基于对象的多态性实现的,也就是说,只有在运行时才能确定调用哪个方法。而静态方法是在编译时就已经确定了调用哪个方法,因此无法进行方法重写。此外,静态方法还有final和private修饰符,这些修饰符也会限制静态方法的重写。
public class A { protected void print1(){ System.out.println("mnnnnnnnnnnnnnnnnnnnnnnnnnnnnn"); } public void print2(int m,int n){ System.out.println("66666666666666666666666666666666666666666"); } }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public class B extends A{ @Override//检查重写方法是否正确,代码可读性也更好 //子类重写父类方法时,访问权限必须大于或等于父类该方法的权限 //void print1(){//error//缺省<protected<public //重写的方法返回值类型必须小于等于父类被重写的方法的返回值类型 //私有方法,静态方法不能重写 //申明不变,重新实现 public void print1(){ System.out.println("100"); } }
import java.util.ArrayList; public class Test { public static void main(String[] args) { Student s = new Student("大牛",50); *System.out.println(s.toString());//方法重写前输出了对象的地址 System.out.println(s);//其实是这里默认调用了toString方法 System.out.println("------------------------------------------"); System.out.println(s.toString());//方法重写后 System.out.println(s);//就近原则 } }
+++++++
@Override public String toString(){ return "Student{name="+name+",age="+age+"}"; } }
子类访问其他成员的特点:
对于变量:
public void print(){ String name="局部变量名"; System.out.println(name);//就近原则:先从局部范围找,然后到子类成员范围找,再到父类范围找,若此时还未找到则报错 System.out.println(this.name);//this的用法 System.out.println(super.name);//父类的成员变量,suer的用法
对于方法:
public void pring1(){ System.out.println("父类的print1方法执行了"); }
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@Override public void pring1(){ System.out.println("子类的print1方法执行了"); } public void showMethod(){ pring1();//执行子类pring1//就近原则 super.pring1();//执行父类Pringl }
子类构造器的特点:
//认识子类构造器的特点 Z z = new Z();
public class F{ public F(){ System.out.println("===父类F的无参数构造器执行了==="); } }
---------------------------------------------------------------
public Z(){ super();//默认存在 System.out.println("===子类Z的无参数构造器执行了==="); } public Z(int n){ System.out.println("===子类Z的有参数构造器执行了==="); } //先输出了===父类F的无参数构造器执行了=== //后输出了===子类Z的无参数构造器执行了=== // 说明子类对象调用子类无参构造器时会先去调用父类的无参构造器再回来执行自己的 Z z2 = new Z(5); //先输出了===父类F的无参数构造器执行了=== //后输出了===子类Z的有参数构造器执行了=== ** 所以子类的全部构造器都会先去调用父类的无参构造器再执行自己的 ** 其实在子类全部构造器的第一行这里都默认存在一个super(); /*public Z(){ super();//默认存在 System.out.println("===子类Z的无参数构造器执行了==="); }*/ //所以如果父类没有无参构造器,子类的全部构造器都会报错
父类没有无参构造器的话必须手写一个有参的super才不报错
public class A { public A(String name,int age){ System.out.println("===父类A的有参数构造器执行了==="); //现在,A中没有无参数构造器 } }
-----------------------
public class B extends A { public B() { super(name:"小华",age:18);//父类没有无参构造器的话必须手写一个有参的super才不报错 System.out.println("===子类B的无参数构造器执行了==="); } }
this的扩展知识:
public student(String name,int age){ /*this.age=age; this.name=name; this.SchoolName="黑马程序⚪";*/ this(name,age,"黑马程序员");//会在将数据传递给下方构造器之后调用下方构造器//需要占据构造器的第一行 //this()与super()不能同时出现 } public student(String name, int age, String schoolName) { this.name = name; this.age = age; SchoolName = schoolName; }
在以上两个构造器中,
/*this.age=age;
this.name=name;
this.SchoolName="黑马程序⚪";*/的作用是将接收的name,age和黑马程序⚪作为这个集合中的name,age和SchoolName的值
它们的作用基本等价于this(name,age,"黑马程序员");
区别是this(name,age,"黑马程序员");调用了第二个构造器而
/*this.age=age;
this.name=name;
this.SchoolName="黑马程序⚪";*/
只是赋值了成员变量
这就是this的作用,即在类的构造器中,通过this(。。。。)调用兄弟构造器
//this()与super()不能同时出现,因为他们都需要放在构造器的第一行
面向对象:多态
认识多态:
多态的前提:1.有继承关系2.有重写方法3.由父类引用指向子类对象
//在继承/实现情况下的一种现象,表现为:对象多态,行为多态 People p1=new Student(); People p2=new Teacher(); p1.run();//"不想跑" p2.run();//"不会跑" //人的行为在不同的对象下表现出不同的特征 这就叫做行为多态 //识别技巧:编译看左边,运行看右边 即编译是到左边去寻找对象和方法,但运行右边的同名方法 //对于变量:编译看左边,运行看左边
成员访问的特点:1.访问成员变量时,访问的是父类中的变量,如果子类中没有则报错
访问成员方法时,如果子类也重写了方法,则访问子类中的重写方法,否则访问子类继承的方法如果父类中没有访问的方法,就不能直接访问子方法
多态的好处:
1.在多态形势下,对象是解耦合(又称松耦合)的,更便于拓展和维护
2.使用父类类型的形参,可以接受一切子类对象,拓展性更强更便利
多态的缺点:
缺点:无法调用子类的独有功能
可以通过强制类型转换解决
但会出现类型转换异常
用instanceof判断当前对象的真实类型
public static void shortcoming(){
// //多态下不能使用子类的独有功能
// //1.自动类型转换:父类 变量名=new 子类();
// //例如:People p=new Teacher();
// //2.强制类型转换:子类 变量名=(子类)父类变量;
// //例如:Teacher t=(Teacher)p;
//
面向对象:抽象
认识抽象类:
//abstract 关键字,可以用它来可以用它来修饰类和方法
public abstract class A {}
上面A类即为抽象类
//抽象类不一定有抽象方法,但有抽象方法的一定要是抽象类
public abstract String A();//抽象方法 public abstract void A(int a);//抽象方法
像上面两个,抽象方法不能有方法体(大括号和其之内的东西)否则就会报错。
//类有的东西抽象类都可以有
//抽象类不能创建对象仅作为一种特殊的父类让子类继承并实现
//一个类继承了抽象类必须将它的抽象方法全部重写,否则自己也要是抽象类
@Override public String A() { return null; } @Override public void A(int a) { }
重写后类似于以上两例.
抽象类的应用场景:
模板方法设计模式。
public abstract class A { public final void write() {//建议用final修饰模板方法,防止重写 System.out.println("牛啊牛啊"); System.out.println(WriteMain()); } public abstract String WriteMain(); }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
public class B extends A{ @Override public String WriteMain() { return "tainiule"; } }
其中A为模板,B为子类,应用模板,提高代码的复用性
使用该方法时需要另写一个类
public class Test { public static void main(String[] args) { B b = new B(); //模板方法设计模式 b.write();//输出:牛啊牛啊+tainiule C c=new C(); c.write(); } }
建议用final修饰模板方法,因为要防止子类重写模板方法,万一模板方法被子类重写那么程序就失效了
面向对象:接口
认识接口:
//在接口中定义成员变量默认为常量
//成员变量(常量) String SCHOOL_NAME="黑马程序员";
//在接口中定义成员方法默认为抽象方法
//成员方法(抽象) void School();
//接口中除了成员变量和成员方法外不能有其它东西; // A a=new A();接口不能创建对象 // 实现接口的类称为实现类 //实现类必须重写完全部接口的全部抽象方法,否则实现类需要定义为抽象类
自jdk8开始,java新添加了一些接口方法
/**
* 1.默认方法,必须使用default修饰默认被public修饰,可以带方法体
* 默认方法就是实例方法,也就是对象的方法,但接口不能创建对象,这时就必须通过实现类的对象来访问默认接口
* */
default void test1(){
System.out.println("===默认方法===");
}
B b=new B(); b.test1();//输出===默认方法===
默认方法需要创建出它的实现类对象,通过实现类对象来调用默认方法
/**
* 2.私有方法,带有方法体,必须使用private修饰 jdk 9开始才支持
* 实例方法,对象的方法
*/
/**
* 3.静态方法:必须使用static修饰
static void test3(){ System.out.println("===静态方法===")
}
A.test3();//输出===静态方法===
静态方法直接用接口名称来找到静态方法
*/
面向对象:内部类
成员内部类:
内部类是类中的5大成分(成员变量,方法,构造器,代码块,内部类)之一,当一个类定义在另一个类的内部那么这些类就叫做内部类
private int age=99;
public class Inner{
public String name;
private int age=88;
//public static String SchoolName;//jdk16开始才支持在内部类中定义类变量
public void test(){
//可以直接访问外部类一些成员
System.out.println(a);
System.out.println(age);
int age=66;
System.out.println(age+"局部变量");//66
System.out.println(this.age+"内部类成员变量");//88
System.out.println(Outer.this.age+"外部类成员变量");//99
外部类名.this可以拿到当前的外部类对象
//Outer.this指定访问当前所在的外部类对象
}
//成员内部类就是类中的一个普通成员类似于之前的普通成员变量,成员方法
//成员内部类的用法
Outer.Inner in=new Outer().new Inner();
in.name="";
in.test();
in.getName();
in.setName("");
创建对象的格式:
外部类名.内部类名 对象名=new 外部类().new 内部类();
静态内部类:
//有static修饰的内部类称为静态内部类,属于外部类自己持有
public static class Inner{}
外部类有的东西内部类都可以有
创建静态内部类对象:
Outer.Inner in=new Outer.Inner();
in.setName("");
in.getName();
in.test();
对于静态内部类中的类变量和类方法的访问使用外部类名.内部类名.变量名/方法名
public static class Inner{
public static int a;
public static void SchoolName(){ }
}
Outer.Inner.a=5;
Outer.Inner.SchoolName();
静态内部类可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员
局部内部类:
//局部内部类是定义在方法中,代码块中,构造器抽象类,接口等执行体中
匿名内部类:
//匿名内部类是一种特殊的局部内部类;(定义在方法中,代码块中,构造器抽象类,接口等执行体中的特殊类) //匿名指:程序员不需要为这个类声明名字
public class Test {
public static void main(String[] args) {
//一种特殊的局部内部类;(定义在方法中,代码块中,构造器抽象类,接口等执行体中的特殊类)
//匿名指:程序员不需要为这个类声明名字
特点:匿名内部类本质就是一个子类,并会立刻创建出一个子类对象
作用:更方便创建子类对象
// animal a=new Cat();
// a.cry();
//计算机在这是会做两件事情
//1.把这个匿名内部类编译为一个子类
//2.立即创建一个子类对象,编译为class文件后里面会出现extends animal;
//以下既是一个子类又是一个子类对象所以可以在前面添加animal a=
animal a=new animal(){
@Override
public void cry() {
System.out.println("喵~~~~~~~~~~~~~!!!!");
}
};
//添加animal a=之后就可以用a对象去执行了
a.cry();//喵~~~~~~~~~~~~~!!!!
}
}
--------------------------------------------------------------------------------------------
abstract class animal{ public abstract void cry(); }
匿名内部类使用:
public class Use {
//通常作为一个参数传输给方法
public static void main(String[] args) {
go(new Swimming(){
@Override
public void swim() {
System.out.println("狗游泳");
}
});
匿名内部类核心目的是简化对象
//go(() -> System.out.println("狗游泳"));这是以上的简化模式
}
//设计一个方法,可以接收一切实现类对象来参加游泳比赛
public static void go(Swimming s){//这个s就可以接收一切实现类对象
System.out.println("start------------------------------------------------------------");
s.swim();
}
}
interface Swimming{
void swim();
}
匿名内部类一般用于调别人的api时使用
面向对象:枚举
认识枚举:
//枚举是一种特殊的类
//第一行必须用来罗列枚举对象名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象
//枚举类的构造器都是私有的(写不写都是私有的),因此,枚举类对外不能创建对象
//枚举都是最终类,不可以被继承
//枚举类中,从第二行开始可以定义类的其他各种成员
public enum A {
//第一行必须用来罗列枚举对象名称
//第二行可以用来写类的那五大成员
X,Y,Z;第一行,列举对象(常量)
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
抽象枚举:
有抽象方法的枚举
由于它不能创建对象,所以不能像普通枚举一样直接罗列对象
应该重写像匿名内部类一样写个括号
X("李四"){ @Override public void go() { System.out.println(getName()+"zai"); } },Y("张三"){括号之间以“,”间隔把B对象里的名字赋成张三 @Override public void go() { System.out.println(getName()+"buzai");//张三buzai } };
B(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public abstract void go();
用枚举实现单例模式:
public enum C{
X;//单例目的:确保一个类只有一个对象
}
-------------------
使用枚举:
public enum Use { BOY,GIRL; }
-------------------
public static void main(String[] args) { check(Use.BOY); } public static void check(Use sex){ switch (sex){ case BOY: System.out.println("1"); break; case GIRL: System.out.println("2"); break; } }
---------------------------------------------------------------------------
使用常量:
public class Constant { public static final int BOY=0; public static final int GIRL=1; }
--------------------
使用常量:
缺点无法限制用户输入参数
public static void main(String[] args) { check(Constant.BOY); } public static void check(Use sex){ switch (sex){ case 0: System.out.println("1"); break; case 1: System.out.println("2"); break; } }
面向对象:泛型
认识泛型:
public class Test {
//定义类,接口,方法时,同时声明了一个或多个类型变量(如<E>),称之为泛型类,泛型接口,泛型方法,他们统称为泛型
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();//从jdk1.7开始,后面的类型可以不声明
list.add("java1");
list.add("java2");
list.add("java3");
list.add(new cat());会报错,因为
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
泛型的本质:把具体的数据类型作为参数传给类型变量
定义泛型类:
public class MyArrayList<E> {
Object ar[]=new Object[100];
private int size;
public boolean add(E e){
ar[size++]=e;
return true;
};
public E get(int index){
return (E) ar[index];
};
}
使用:
public class Test {
public static void main(String[] args) {
MyArrayList list=new MyArrayList();
list.add("nb");
list.add(111454);
System.out.println(list.get(0));
System.out.println(list.get(1));
}
}
定义泛型接口:
import java.util.ArrayList;
public interface Data<T> {
void add(T t);
ArrayList<T> getByName(String name);
}
设计对应的实用类:
public class Teacher implements Data<Teacher>{
@Override
public void add(Teacher teacher) {
}
@Override
public ArrayList<Teacher> getByName(String name) {
return null;
}
}
注意两个代码块add后面的不同,Teacher中,将T泛型限制为Teacher类型
这样通过
Teacher t=new Teacher();
t.add();输入的仅能是Teacher类型的
泛型方法:
修饰符 <类型变量,类型变量,......> 返回值类型 方法名(形参列表){}
public static <E> void test(T t){}
通配符:
就是?,
?可以代表一切类型并且也可以写<? extends car>只能接收car的子类(上限)
<? super car>只能接受car和car的父类(下限)
注意事项:
1.泛型是工作在编译阶段的,一旦编译成class文件,class文件中就不存在泛型了,这就是泛型擦除
ArrayList<String> list=new ArrayList<>(); // 类似上方集合,在class文件中,<String>,<>都不见了,这就是泛型擦除
//2.泛型不支持基本数据类型,只支持对象类型(引用数据类型)
ArrayList<Integer> list1=new ArrayList<>();
//Integer// 是int的引用类型形式
ArrayList<Double> list2=new ArrayList<>();
//Double//是double的引用类型形式