4月2日,MLDN学习记

我在写日志的时候将泛型又重新写一分更好的,跟大家分享吧.

今天所讲的知识点
A 泛型的引出
B 泛型类
C 擦除泛型
D 通配符?
E 泛型上限和泛型下限
F 泛型接口
G 泛型方法
H 泛型的嵌套设置


我对知识点的分析
A 泛型的引出
当需要定义一个能接受多种数据类型的数据的类的时候,原来只能采用把其属性、setter方法的参数、getter方法的返回值的数据类型设置成Object类型,虽然这样做可以实现。在设置值的时候还要说,自动发生向上转型,但是在取出数据的时候总是涉及到强制的向下转型。
问题:
1、总是需要强制类型转换
例如:
public class Point { // 表示坐标
private Object x;
private Object y;
public Object getX() {
  return x;
}
public void setX(Object x) {
  this.x = x;
}
public Object getY() {
  return y;
}
public void setY(Object y) {
  this.y = y;
}
}
public class GenDemo01 {
public static void main(String[] args) {
  Point p = new Point();
  p.setX(11); // int --> Integer --> Object
  p.setY(20); // int --> Integer --> Object
  int x = (Integer) p.getX(); // 取出x坐标
  int y = (Integer) p.getY();// 取出y坐标
  System.out.println("x的坐标是:" + x);
  System.out.println("y的坐标是:" + y);
}
}
2、存在安全漏洞
因为其类型是Object类型,所以能接受所有的数据类型的对象。这样在取出数据的时候就不能确定能发生的向下类型操作。
例如:前面传入的字符串,而后面取出的时候可能向下转成了Integer,这样就会发生和报告错误。
public static void main(String[] args) {
  Point p = new Point();
  p.setX(10);
  p.setY("北纬220度");//此处不报错
  int x = (Integer) p.getX(); // 取出x坐标
  int y = (Integer) p.getY();// 取出y坐标    不可以
  System.out.println("x的坐标是:" + x);
  System.out.println("y的坐标是:" + y);
}


如上的两个问题可以通过泛型技术得到解决。
B 泛型类
定义格式:
class 类名称<泛型类型,泛型类型,…>{

}
即类中的数据类型,可以由外部实例化该类的对象的时候决定。
例如:
public class Point<T> { // 表示坐标
private T x; // x属性的类型由外部决定
private T y; // y属性的类型由外部决定
public Point(T x, T y) {//构造方法的参数类型也使用了泛型
  this.setX(x);
  this.setY(y);
}
public T getX() {
  return x;
}
public void setX(T x) {
  this.x = x;
}
public T getY() {
  return y;
}
public void setY(T y) {
  this.y = y;
}
}
-------------------------------
public static void main(String[] args) {
  Point<Integer> p = new Point<Integer>(10, 20);
  int x = p.getX(); // 取出x坐标
  int y = p.getY();// 取出y坐标
  System.out.println("x的坐标是:" + x);
  System.out.println("y的坐标是:" + y);
}

C 擦除泛型
如果一个类定义的时候使用了泛型,但是在使用该类的时候没有指定泛型的话,则表示擦除泛型。
泛型一旦擦出之后,将按照Object进行接收,以保证程序不出现任何的错误。
例如:
public static void main(String[] args) {
  Point p = new Point(10, 20);//此处未指定泛型的具体类型,将按照Object进行接收
  int x = (Integer) p.getX(); // 取出x坐标
  int y = (Integer) p.getY();// 取出y坐标
  System.out.println("x的坐标是:" + x);
  System.out.println("y的坐标是:" + y);
}


D 通配符?
泛型类,在使用的时候,指定Integer时和Object类型两个对象不存在可以转型的关系。
例如:
Point<Object> p1 = new Point<Object>();
Point<Integer> p2 = new Point<Integer>() ;
p1 = p2 ; // 此时无法转换

那么这个局限,在设置方法参数的时候就导致了很大的麻烦!!!
例如由此方法的定义:
public static void fun(Point po) {//如果此处不指定Point的泛型,则虽然可以接受任意类型的对象,但是是按照泛型擦除处理的,即以Object处理,又回到了原来没有泛型的问题上
}

public static void fun(Point<具体类型> po) {//如果此处指定Point的泛型,则又导致只能接受所指定的类型的对象,其他类型的对象就不可以
}
例如:public static void fun(Point< Integer > po) {},则此方法p2能调用,p1就不能调用
所以需要采用通配符?
“?”表示的是可以接收任意的泛型类型
例如:public static void fun(Point<?> po) {},这样可以接受任意类型的对象
但是只是接收输出,并不能修改
例如:
public static void fun(Point<?> po) { // 表示,此时可以接收任意的类型
         po.setX(“aa”);//错误,不能修改,因为无法确定其传入的对象的类型到底是什么,此处指定其setX()参数为字符串类型,太绝对了
  System.out.println(po.getX());
  System.out.println(po.getY());
}


E 泛型上限和泛型下限
1、泛型上限
上限就指一个操作泛型其最大的操作父类
设置型的上限语法:<T  extends  类名>,表示泛型T只能是此处指定的类型或者其子类,而不可超越此类,即不能指定其他类或者其父类。例如:现在最大的上限设置成“Number”类型,那么此时,所能够接收到的类型只能是Number及其子类(Integer)。
public class Point<T extends Number> { // 表示坐标,最高只能是Number
……………….
}
以上的泛型类型明确的指出,最大的操作父类是Number,能设置的内容只能是其子类Integer、Float等等。

2、泛型下限
泛型的下限指的是只能设置其具体的类或者父类。
设置的语法如下:<T  super  类名>
例如:现在下限设置成“Number”类型,那么此时,所能够接收到的类型只能是Number或其父类。

F 泛型接口
定义格式:interface 接口名称<泛型类型,泛型类型,…>{}
例如:
public interface Demo<T> { // 定义泛型接口
public void print(T param);//  此抽象方法中使用了泛型类型
}

实现接口的方法:
1、在实现接口的类上继续标记泛型
public class DemoImpl1<T> implements Demo<T> {
public void print(T param) {
  System.out.println("param = " + param);
}
}
-----------------------------------
public static void main(String[] args) {
  Demo<String> demo = new DemoImpl1<String>() ;
  demo.print("hello") ;
}
2、实现接口的时候指定具体的类型
public class DemoImpl2 implements Demo<DemoImpl2> {// 设置具体类型
public void print(DemoImpl2 param) {
  System.out.println("param = " + param);
}
}
因为此处指定的类型为DemoImpl2,其本身,所以此处不需要在类名后面指定< DemoImpl2>,如果此处指定的是其他类型,则还需要在类名后面加上<其他类型>
public static void main(String[] args) {
  Demo<DemoImpl2> demo = new DemoImpl2() ;
  demo.print(new DemoImpl2()) ;
}

G 泛型方法
在方法上使用泛型,此方法所在的类不一定是泛型的操作类
权限修饰符 <泛型>  返回值类型 print(参数列表){}
方法的返回值类型及其中的变量的数据类型都可以用该泛型指定。
一般其中参数都有一个是泛型指定的,那么在调用该方法的时候,根据所传递的实参的数据类型来决定该泛型的具体类型。
例如:
class Demo {
public <T> T print(T param){ // 定义泛型方法
  return param ;
}
}
public class GenDemo17 {
public static void main(String[] args) {
  Demo d = new Demo() ;
  System.out.println(d.print(1)); // 如果输入1表示类型是Integer
}
}
-----------------------------------------------------------------------------
public class GenDemo18 {
public static void main(String[] args) {
  Integer i[] = fun(1, 2, 3, 4, 5, 6, 7, 8, 9);
  for (int x : i) {
   System.out.println(x);
  }
}
public static <T> T[] fun(T... param) {
  return param; // 返回数组
}
}


H 泛型的嵌套设置
当一个类是泛型类,在实现其类的时候指定的数据类型是另一个包含泛型的类,那么这个时候就需要依次指定泛型。
例如:有一个Info泛型类
public class Info<T> {
private T param ;
public T getParam() {
  return param;
}
public void setParam(T param) {
  this.param = param;
}
}
另一个泛型类Person
public class Person<T> {
private T infos;
public T getInfos() {
  return infos;
}
public void setInfo(T info) {
  this.infos = info;
}
}
此时在实例化Person的时候指定的类型是Info类型,因为Info本身也是泛型类,那么就要先指定Info类的泛型,然后指定Person类的泛型,例如:
public static void main(String[] args) {
        //同时即要指定Person的泛型类型,又要指定Info中的泛型类型,依次指定
  Person<Info<String>> per = new Person<Info<String>>() ;
  per.setInfo(new Info<String>()) ;
  per.getInfo().setParam("mldnjava") ;
  System.out.println(per.getInfo().getParam()) ;
}




今天的问题


A public static void main(String[] args) {
String info="张三:21:98|李四:22:89|王五:20:70";
String []str=info.split("\\|");//按"|"把每个学生的信息拆分开来
Student stu[]=new Student[str.length];//根据之前拆分的学生信息的个数来确定学生对象数组大小
for(int i=0;i<stu.length ;i++){
  String []temp=str[i].split(":");

  stu[0].setName(temp[0]);//空指向异常
  stu[0].setAge(Integer.parseInt(temp[1]));//空指向异常
  stu[0].setScore(Integer.parseInt(temp[2]));//空指向异常
}
}

解决方法:
public static void main(String[] args) {
  String info="张三:21:98|李四:22:89|王五:20:70";
  String []str=info.split("\\|");//按"|"把每个学生的信息拆分开来
  Student stu[]=new Student[str.length];//根据之前拆分的学生信息的个数来确定学生对象数组大小
  for(int i=0;i<stu.length ;i++){
   String []temp=str[i].split(":");
   stu[i]=new Student(temp[0],Integer.parseInt(temp[1]),Integer.parseInt(temp[2]));
  }
}

问题描述:
对象数组的每一个元素都需要进行实例化
前天关于泛型部分不是很懂。今天看了一些资料,分析了一下代码,基本明白了。
今天在做作业题的时候犯了了对象数组元素未实例化的错误,一直报空指向异常,找了好久才找出原因,以后一定要记住。



你可能感兴趣的:(F#)