JAVA学习之路

  1. 在开发时, 一个项目中可能会使用很多包,当一个包中的类需要调用另一个包中的类时,就需要使用import关键字引入需要的类。使用import可以在程序中一次导入某个指定包下的类,这样就不必在每次用到该类时都书写完整类名,简化了代码量。使用import 关键字的具体格式如下所示:
    import包名.类名;
    需要注意的是,import 通常出现在package 语句之后,类定义之前。如果有时候需要用到一个包中的许多类,则可以使用
    import 包名.*;
    来导入该包下所有类。
    在JDK中,不同功能的类都放在不同的包中,其中,Java的核心类主要放在java包及其子包下,Java扩展的大部分类都放在javax 包及其子包下。为了便于后面的学习,接下来简单介绍Java语言中的常用包。
  • java.util:包含Java中大量工具类、集合类等,例如:Arrays、List、Set等。
  • java.net:包含Java网络编程相关的类和接口。
  • java.io:包含了Java输入、输出有关的类和接口。
  • java.awt:包含用于构建图形界面(GUI)的相关类和接口。
  1. Java中的程序代码可分为结构定义语句和功能执行语句,其中,结构定义语句用于声明一个类或方法,功能执行语句用于实现具体的功能。每条功能执行语句的最后都必须用分号(;)结束。如下面的语句:
    System.out.printIn ("这是第个Java程序! ") ;

  2. Java程序中一句连续的字符串不能分开在两行中书写。例如,下面这条语句在编译时将会出错。

System.out.println ("这是第一个
Java程序! ") ;

如果为了便于阅读,想将一个太长的字符串分在两行中书写,可以先将这个字符串分成两个字符串,然后用加号(+ )将这两个字符串连起来,在加号(+)处断行,上面的语句可以修改成如下形式。

System. out .println ("这是第一个”+
"Java程序! ") ;
  1. 在Java程序中定义的标识符必须要严格遵守上面列出的规范,否则程序在编译时回报错。除了上面列出的规范,为了增强代码的可读性,建议初学者在定义标识符时还应该遵循以下规则。
  • 包名所有字母律小写。例如: cn.tast.test
  • 类名和接口名每个单词的首字母都要大写。例如:ArrayListIteratoro
  • 常量名所有字母都大写,单词之间用下划线连接。例如: DAY. OF_MONH
  • 变量名和方法名的第一个单词首字母小写, 从第2个单词开始,每个单词首字母大写。例如:lineNumbergetL ineNumber
  • 在程序中,应该尽量使用有意义的英文单词来定义标识符,使得程序便于阅读。例如使用userName表示用户名,password表示密码。
  1. byte 1个字节
    short 2个字节
    char 2个字节 0~65535范围的整数。
    int 4个字节
    long 8个字节
    float 32位(4个字节)
    double64位(8个字节)
    long类型的变量赋值时需要注意,所赋值的后面要加上一个字母L(或者小写l),以此说明是long类型。若赋的值未超出int型的取值范围,则可以省略字母L(或者小写l)
  2. 浮点数类型变量 ,再取值范围中,E(或者小写e)表示以10为低的指数。
    在Java当中一个小数值会被默认为double类型的值,因此在为一个float类型的变量赋值时,应该注意后面一定要加上字母F(或者小写f)
    eg:float f = 123.4f;
    在程序中可以为以个浮点数类型变量赋予一个整数数值。
  3. 自动类型转换
    自动类型转换也叫隐式类型转换.指的是两种数据类型在转换的过程中不需要显式地进行声明。要实现自动类型转换,必须同时满足两个条件,第一是两种数据类型彼此兼容, 第二是**目标类型的取值范围大于源类型的取值范围。**例如:
byteb=3;
int x=b;  //程序把byte类型的变量b转换成了int类型,无需特殊声明

上面的语句中,将byte类型的变量b的值赋给int类型的变量x,由于int 类型的取值范围大于byte类型的取值范围,编译器在赋值过程中不会造成数据丢失,所以编译器能够自动完成这种转换,在编译时不报告任何错误。
除了上述示例中演示的情况,还有很多类型之间可以进行自动类型转换,接下来就列出3种可以进行自动类型转换的情况,具体如下。
①整数类型之间可以实现转换,如byte类型的数据可以赋值给short、 int、 long类型的变量,short、char 类型的数据可以赋值给int、long 类型的变量,int 类型的数据可以赋值给long类型的变量。
❷整数类型转换为float类型,如byte、char、 short、 int类型的数据可以赋值给float类型的变量。
③其他类型转换为double类型,如byte、 char、 short、 int、 long、 float类型的数据可以赋值给double类型的变量。

  • 强制类型转换
    强制类型转换也称为显式类型转换,指的是两种数据类型之间的转换需要进行显式的声明。当两种类型彼此不兼容,或者目标类型取值范围小于源类型时,自动类型转换无法进行,这时就需要进行强制类型转换。eg:
public class Example01{
	pblic static void main (String[] args){
		int num = 4;
		byte b =num;
		System.out.println(b);
	}
}

程序将会报错,提示数据类型不匹配。
这种情况需要用到强制类型转换。具体格式如下:
目标类型 变量 = (目标类型) 值
eg:byte b = (byte) num;
需要注意的是,在对变量进行强制类型转换时,会发生取值范围较大的数据类型向取值范围较小的数据类型的转换。很容易造成数据精度的丢失。

  • 表达式类型自动提升
    表达式:由变量和运算符组成的一个算式。变量在表达式的运算中进行运算时,也又可能发生自动类型的转换。如一个byte类型的变量在运算期间类型会自动提升为int型。
public class Example03{
	public static void main (String[] args){
		byte b1 - 3;
		 byte b2 = 4;
		 byte b3 = b1 + b2 ;
		 System.out.println("b3="+b3);
	}
}

编译报错。表达式b1+b2运算期间,变量b1和b2都被自动提升为int型,表达式的运算结果就成了int型,这时如果将结果给byte型的变量就会报错,需要进行强制转换。修改后:

 public class Example03{
 	public static void main (String[] args){
 		byte b1 - 3;
 		 byte b2 = 4;
 		 byte b3 = (byte)   (b1 + b2 );
 		 System.out.println("b3="+b3);
 	}
 }
  1. 赋值运算符
  • 在进行除法运算时,当除数和被除数都为整数时,得到的结果也是一个整数。 如果除法运算有小数参与,得到的结果会是一个小数。例如,2510/1000 属于整数之间相除,会忽略小数部分,得到的结果是2,而2.5/10的结果为0.25。
    请思考一下下面表达式的结果是多少。3500/1000*1000
    结果为3000由于表达式的执行顺序是从左到右,所以先执行除法运算3000得到结果为3,再乘以1000,得到的结果自然就是3000了。
  • 在进行取模(% )运算时,运算结果的正负取决于被模数(%左边的数)的符号,与模数(%右边的数)的符号无关。如:(-5)9%3–2, 而5%(-3)=2。
  1. 对象和类的概念产生对象在这里插入图片描述
    在这里插入图片描述 在这里插入图片描述

  2. 对象=属性+ 方法
    对象的范围=属性定义+方法定义
    对象是一个变量(具体的东西)

  3. 方法
    就是一段可以重复调用的代码。
    根据不同的操作,将代码分别放在不同的{}中,并分别为这些代码起名。
    需要注意的是,在有些书中也会把方法称为函数。这两者本身没有什么区别,是同样的概念。
    方法的重载
    注意:方法重载的返回值类型通常都是相同的。

方法重载的目的是,功能类似的方法使用同一名字,更容易记住,因此,调用起来更简单。

package java_example;

public class Example23 {
//重载是同一个方法名可以多用
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int add1 = add(1,2);
		int add2 = add(1,2,3);
		double add3 = add(1.2,2.2);
		System.out.println("add1="+add1);
		System.out.println("add2="+add2);
		System.out.println("add3="+add3);

	}
	//实现两个整数的相加
	public static int add(int x,int y) {
		return x+y;
	}
	//实现三个整数的相加
	public static int add(int x,int y,int z) {
		return x+y+z;
	}
	//实现两个双精度数的相加
	public static double add(double x,double y) {
		return x+y;
	}

}
  1. 数组的定义
    定义数组的方法
  • int [] arr;
    arr = new int [3];
  • int [] arr = new int [3];
  • int [] arr = {1,2,3,4};

在程序中可以使用“数组名.length”的方式来活得数组的长度,即元素的个数。

package java_example;

public class Example24 {

   public static void main(String[] args) {
   	// TODO Auto-generated method stub
   	int [] arr;
   	arr = new int [3];
   	System.out.println("arr[0]="+ arr[0]);
   	System.out.println("arr[1]="+ arr[1]);
   	System.out.println("arr[2]="+ arr[2]);
   	System.out.println("arr.length= " +arr.length);
   }

}

动态初始化:在定义数组时只指定数组的长度,由系统自动为元素赋初值的方式。
静态初始化:在定义数组的同时就为数组的每个元素赋值。

eg:

  • 类型 [ ] 数组名 = new 类型 [ ]{元素,元素,元素,……};
  • 类型 [ ] 数组名 = {元素,元素,元素,……};
千万不能写成 int [] x=new int [4]{1,2,3,4}; 这样写编译器会报错。原因是编译器会认为数组限定的元素个数[4]与实际存储的元素{1,2,3,4}个数又可能不一致,存在一定的安全隐患。

每个数组的索引都有一个范围,即0~length-1.
14. 如果不确定是否需要public,就不声明为public,即尽可能少地暴露对外的字段和方法。

把方法定义为package权限有助于测试,因为测试类和被测试类只要位于同一个package,测试代码就可以访问被测试类的package权限方法。

一个.java文件只能包含一个public类,但可以包含多个非public类。如果有public类,文件名必须和public类的名字相同。
小结

Java内建的访问权限包括public、protected、private和package权限;

Java在方法内部定义的变量是局部变量,局部变量的作用域从变量声明开始,到一个块结束;

final修饰符不是访问权限,它可以修饰class、field和method;

一个.java文件只能包含一个public类,但可以包含多个非public类。


各种方法

  • System.out.println(Arrays.to.String(数组名))这个函数可以遍历输出数组的值
  • Arrays.sort(数组名);该函数可以为数组从小到大排序
    eg:
package java_example;

import java.util.Arrays;

public class practic {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] ns = {32,41,45,123,451,2,12,54,41};
		Arrays.sort(ns)
		System.out.println(Arrays.toString(ns));
	}

}

  • indexOf()方法返回的是搜索的字符或者字符串首次出现的位置。indexOf(String s)如果没有检索到字符串s,该方法的返回值是-1。
String str = "We are students";
int size = str.indexOf("a");        //变量size的值是3
 									//We are
 									//012345
  • lastIndexOf()方法返回的是搜索的字符或字符串最后一次出现的位置.
    lastIndexOf(String str)如果没有检索到字符串s,该方法的返回值是-1。
  • charAt()方法可将指定索引处的字符返回。
String str = "hello world";
char mychar = str.charAt(6);     //将字符串str中索引位置是6的字符w返回。
  • String类的substring()方法可对字符串进行截取。
    substring()方法背两种不同的方法重载。
    (1)substring(int beginIndex)
    该方法返回的是从指定的所以位置开始截取直到该字符串结尾的字串。
    eg:
String str = "Hello World";
String substr = str.substring(3);  			//获取字符串,substr值为lo World

(2)substring(intbeginIndex,int endIndex)
该方法返回的是从字符串某一索引位置开始截取至某一索引位置结束的字串。
eg:

String str = "hello world";
String substr = str.substring(0,3);		//截取出字符串hel
  • trim()方法返回字符串的副本,忽略前导空格尾部空格
    eg:
String str = "    Java   class";
System.out.println("字符串原来的长度:"+str.length());				//16
System.out.println("字符串后来的长度:"+str.trim().length());		//4+3+5= 12
  • replace()方法可实现将指定的字符或字符串替换成新的字符或字符串
    语法:str.replace(char oldChar,char newChar)
    oldChar:要替换的字符或字符串
    newChar:用于替换原来字符串的内容
    eg:
    String str = "address";
    String newstr = str.replace("a","A"); 		//将字符串str中的a替换成A
    System.out.println(newstr);				//输出替换后的字符串"Address"
    
    • 判断字符串的开始与结尾
      (1)startsWith()该方法用于判断当前字符串对象的前缀是否为参数指定的字符串。
      语法:str.startWith(String perfix) prefix 是指作为前缀的字符。
      (2)endsWith该方法用于判断当前字符串是否为以给定的字符串结束。
      语法:str.endWith(String suffix) suffix是指作为后缀的字符串。
      eg:
/*
判断正确boolean值为true
判断错误boolean值为false
*/
String num1 = "22045612";
String num2= "21304578";
boolean b = num1.startsWith("22");		//判断num1是否以“22”开头
boolean b2 = num1.endsWith("78");		//判断num1是否以“78”结尾
boolean b3 = num2.startsWith("22");		//判断num2是否以“22”开头
boolean b4 = num2.endsWith("78");		//判断num2是否以“78”结尾

  • 比较运算符“==”比较的是两个字符串的地址是否相同
  • equals()方法:如果两个字符串具有相同的字符和长度,则使用equals()方法进行比较时,返回true。(区分大小写)
  • equalsIgnoreCase()方法:(忽略大小写)比较两个字符串是否相等,返回结果仍为boolean类型。
  • compareTo方法为按字典顺序比较两个字符串。该比较基于字符串中各个字符的Unicode值,按字典顺序将此String对象表示的字符序列与参数字符串所表示的字符序列进行比较。
    结果:如果此String对象位于参数字符串之前,则比较结果为一个负整数;如果按字典顺序此String对象位于参数字符串之后,则比较结果为一个正整数;如果这两个字符串相等,则结果为0。
    eg:
String str = new String("b");
String str2 = new String("a");
String str3 = new String("c");
System.out.println(str + "compareTo" + str2 + ":"
					+ str.compareTo(str2));				//将str与str2比较的结果 1 输出
System.out.println(str + "compareTo" + str3 + ":"
					+ str.compareTo(str3));				//将str与str3比较的结果 -1 输出
  • toLowerCase()方法可将字符串中的所有字符从大写字母改写为小写字母。
    格式:str.toLowerCase()
  • toUpperCase()方法可将字符串中的小写字母改写为大写字母。
    格式:str.toUpperCase()
  • split()方法可以使字符串按指定的分割字符或字符串对内容进行分割,并将风格后的结果存放在字符串数组中。

(1)split(String sign)
该方法可根据给定的分隔符对字符串进行拆分。
语法: str.split(String sign)

(2)split(String sign,int limit)
该方法可以根据给定的分割符对字符串进行拆分,并限定拆分的次数。
语法: str.split(String sign,int limit)

字符串转换成字节数组

String msg = "IO is so esay";
byte [] datas = msg.getBytes();

字节数组转换成字符串

//String构造方法有解码功能,并且默认编码是utf-8
byte[] datas = new byte[10];
String msg = new String(datas);

多态

多态专业定义则是:程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误 ,如果有,执行的是子类重写后的方法

在创建子类对象时,会先去调用父类的构造器,而父类构造器中又调用了被子类覆盖的多态方法,由于父类并不清楚子类对象中的属性值是什么(先初始化父类的时候还没开始初始化子类)

“绑定”的概念:

绑定指的是一个方法的调用与方法所在的类(方法主体)关联起来,大致可以理解为一个方法调用另一个方法。
对java来说,绑定分为静态绑定和动态绑定;或者分别叫做前期绑定和后期绑定。
静态绑定(前期绑定)
针对java静态绑定简单的可以理解为程序编译期的绑定
动态绑定(后期绑定)
简明的说动态绑定就是指编译器在编译阶段不知道要调用哪个方法,运行期才能确定
区别:
1、静态绑定是发生在编译阶段;而动态绑定是在运行阶段;
2、静态绑定使用的是类信息,而动态绑定使用的是对象信息
3、重载方法(overloaded methods)使用的是静态绑定,而重写方法(overridden methods)使用的是动态绑定
父类中被重写的方法都是虚方法(virtual)

向上转型

向上转型:多态本身是子类类型向父类类型向上转换的过程,其中,这个过程是默认的。你可以把这个过程理解为基本类型的小类型转大类型自动转换,不需要强制转换。 当父类引用指向一个子类对象时,便是向上转型。 向上转型格式:

父类类型 变量名 = new 子类类型(); 如:Father f= new Son();

向下转型

向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。同样可以把这个过程理解为基本类型的自动转换,大类型转小类型需要强制转换。一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,向下转使用格式:

Father father = new Son();
子类类型 变量名 = (子类类型) 父类变量名; 如:Son s =(Son) father;

父类引用指向子类对象(也可以说向上转型)
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误 ,如果有,执行的是子类重写后的方法,也就是向上转型时, 子类单独定义的方法丢失问题。编译报错。

当父类对象引用变量引用子类对象时,被引用对象的类型决定了调用谁的成员方法,引用变量类型决定可调用的方法。首先会先去可调用的方法的父类中寻找,找到了就执行子类中覆盖的该方法,就算子类中有现成的该方法,它同样也会去父类中寻找,早到后未必执行子类中有现成的方法,而是执行重写在父类中找到的方法的子类方法(这里的子类也就是最后决定调用的类方法)。
多态的使用

异常

throw用在方法内,后面接一个异常对象,使用格式为throw new 异常类名(参数);,将这个异常对象传递到调用者处,并结束当前方法的执行。
eg:throw new FileNotFoundExpection(“nofound”)

关键字throws运用于方法声明之上,throws格式为修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ },用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
eg:public void main(String[] args) throws FileNotFound{…}

匿名内部类

正所谓匿名内部类,正如它的字面意思一样,也就是没有名字的内部类。也是因为没有名字所以匿名内部类只能执行一次

使用匿名内部类有个前提条件:必须继承一个父类或实现一个接口,但最多只能继承一个父类,或实现一个接口。
特点:
1、匿名内部类不能有构造器(或者构造方法)
2、匿名内部类不能是抽象类
3、匿名内部类可以通过匿名实现匿名内部类的方法,但是不能实现匿名内部类里没有定义的方法。

匿名方法最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口

public class NiMingInnerClassThread {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i<5;i++){
                    System.out.println("熊孩子:"+i);
                }
            }
        };
        new Thread(r).start();
        for (int i = 0; i < 5 ; i++){
            System.out.println("傻狍子:"+i);
        }
    }
}

重写toString()方法

重写toString() 可以理解为是对对象在打印输出时候的一种格式化。这样做符合业务逻辑,显示结果人性化。
1、没有重写tostring ,每执行System.out.println() 会默认调用Object 的toString 方法
在这里插入图片描述2、重写tostring,每执行System.out.println() 会调用重写的toString 方法,情况则会根据重写的方法打印输出成自己想得到的格式。

3、为了养成良好习惯,建议每次编写实现类都重写一下tostring() 方法!!

1.集合Collection

集合:集合是java中提供的一种容器,可以用来存储多个数据。
集合特点:
1、数组长度固定,集合长度可变。
2、 数组中只能是同一类型的元素且可以存储基本数据类型值。集合只能存对象,类型可以不一致。

1.1集合框架

集合按照其存储结构可以分为两大类,分别是单列集合java.util.Collection双列集合java.util.Map。

  • Collection:单列集合类的根接口,用于存储一系列符合某种规则的元素,它有两个重要的子接口,分别是java.util.List和java.util.Set。

List的特点是元素有序、元素可重复。
Set的特点是元素无序,而且不可重复。
List接口的主要实现类有java.util.ArrayList和java.util.LinkedList。
Set接口的主要实现类有java.util.HashSet和java.util.TreeSet。

1.1.1 Iterator迭代器

Iterator主要用于迭代访问(即遍历)Collection中的元素,因此Iterator对象也被称为迭代器。
每个集合对象都有自己的迭代器
Iterator it = coll.iterator();

迭代器的遍历过程:
在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。
在这里插入图片描述

1.1.2增强版for(foreach)

增强后的for(foreach)可以用于遍历数组或者是集合。其内部原理也是一个Iterator迭代器,所以在遍历的过程中不能对集合内部的元素进行修改增删操作。

//遍历数组
String[] st = new String[] {"A","B","C","D"};
		for (String s :st) {
			System.out.println(s);
		}
//遍历集合
Collection<String> coll = new ArrayList<String>();
    	coll.add("李白");
    	coll.add("韩信");
    	coll.add("赵云");
    	//使用增强for遍历
    	for(String s :coll){//接收变量s代表 代表被遍历到的集合元素
    		System.out.println(s);
    	}

1.2 List接口

java.util.List接口继承自Collection接口,在List集合元素可重复、元素有序。所有的元素是以一种线性方式进行存储的,在程序中可以通过索引来访问集合中的指定元素,而且元素的存入顺序和取出顺序一致。

特点:List集合特有的方法都是跟索引相关

    1、元素存取有序:例如,存元素的顺序是“我”、“是”、“佩”、“奇”,那么集合中,元素的存储就是按照“我”、“是”、“佩”、“奇”的顺序完成的。
    2、带有索引的集合:与数组的索引是一个道理
    3、元素可重复:通过元素的equals方法,来比较是否为重复的元素。
1.2.1ArrayList集合

java.util.ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。

1.2.2 LinkedList集合

java.util.LinkedList集合数据存储的结构是链表结构。元素增删快,查找慢的集合。

LinkedList是一个双向链表.
实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。在这里插入图片描述

1.3 Set接口

Set接口中元素无序且不重复
Set集合有多个子类,这里我们介绍其中的java.util.HashSetjava.util.LinkedHashSet这两个集合。
java.util.HashSet底层的实现其实是一个java.util.HashMap支持。
HashSet是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取查找性能。保证元素唯一性的方式依赖于:hashCodeequals方法

1.3.1 HashSet集合存储数据的结构(哈希表)

JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。
JDK1.8中,哈希表存储采用数组+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
在这里插入图片描述总而言之,JDK1.8引入红黑树大程度优化了HashMap的性能,那么对于我们来讲保证HashSet集合元素的唯一,其实就是根据对象的hashCode和equals方法来决定的。如果我们往集合中存放自定义的对象,那么保证其唯一,就必须复写hashCodeequals方法建立属于当前对象的比较方式。
对于HashSet中保存的对象,主要要正确重写equals方法和hashCode方法,以保证放入Set对象的唯一性,虽说是Set是对于重复的元素不放入,倒不如直接说是底层的Map直接把原值替代了(这个Set的put方法的返回值真有意思)。

1.3.2 LinkedHashSet

LinkedHashSet是让HashSet中元素有序化的一个子类
HashSet下面有一个子类java.util.LinkedHashSet,它是链表和哈希表组合的一个数据存储结构

public class LinkedHashSetDemo {
	public static void main(String[] args) {
		Set<String> set = new LinkedHashSet<String>();
		set.add("秃头哥");
		set.add("地中海哥");
		set.add("平头哥");
		set.add("假发哥");
        Iterator<String> it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}
/*
输出结果:
	秃头哥
	地中海哥
	平头哥
	假发哥
*/

泛型

泛型中各个字母所代表的含义
E - Element (在集合中使用,因为集合中存放的是元素)
T - Type(Java 类) T代表在调用时的指定类型
K - Key(键)
V - Value(值)
N - Number(数值类型)
? - 表示不确定的java类型 一般用在通配

集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成Object类型。

		Collection coll = new ArrayList();
		coll.add("aaa");
		coll.add("AAA");
		coll.add(123);
		coll.add(new TestFather());
		Iterator it = coll.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
		/*
I am Father
YES
aaa
AAA
123
TestFather@44c8afef

*/

反射

反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法,所谓反射其实是获取类的字节码文件,也就是.class文件。平时我们要调用某个类中的方法的时候都需要创建该类的对象,通过对象去调用类里面的方法,反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了,在这种情况下(没有创建对象)我们都能够对它的方法和属性进行调用,我们把这种动态获取对象信息和调用对象方法的功能称之为反射机制。

反射才体现出java是如何创建对象的。当java虚拟机(JVM)加载一个class类文件时,就创建这个类的class对象,以后的对象都是由这个class对象创建的,所以同一个类的所有对象的class对象都是一个,比如A a=new A(); A b=new A(); a.class()==b.class()返回true.

在jvm中实例化对象的加载过程。
在这里插入图片描述JDK1.7中 class类的解释
在这里插入图片描述

Class 类的实例表示正在运行的 Java应用程序中的类和接口。也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型) Class 没有公共构造方法。Class对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass方法自动构造的。也就是这不需要我们自己去处理创建Class对象,JVM已经帮我们创建好了。

常用方法
forName(String className)是静态方法,同样可以用来加载类
返回与给定的字符串名称的类或接口相关的 类对象。
获得字符串参数中指定的类,并初始化该类。
getName()
返回此 Class对象所表示的实体(类、接口、数组类、基本类型或 void)名称
newInstance()
为类创建一个实例,但只能调用默认构造器(无参数构造器)

其中的一种使用方法:
forName和newInstance结合起来使用,可以根据存储在字符串中的类名创建对象。例如
Object obj = Class.forName(s).newInstance();

反射的使用

反射的第一步是获取需要被反射的类的Class对象。

获取class对象的三种方法

1、使用Class.forName 静态方法。
当你知道该类的全路径名时,你可以使用该方法获取 Class 类对象【最常用,必须掌握】
2、使用 .class方法。
这种方法只适合在编译前就知道操作的 Class,但是这种方法需要导入类的包,依赖性太强,所以用的比第一种稍微要少 【重点】
3、使用类对象的getClass() 方法。
这种方法已经创建了对象,那么这个时候就不需要去进行反射了,显得有点多此一举。【不常用,了解即可】

//第一种,使用Class.forName 静态方法。
Class Student= Class.forname(“com.FanSe.Student”);//类的全路径名
//第二种,使用 .class方法。
Class Student= 类名.class;//这种方法需要导入类的包,依赖性太强
//第三种,使用类对象的 getClass() 方法。
Student str = new Student();
Class clz = str.getClass();

反射获取构造方法并使用

1).批量获取构造方法:
public Constructor[] getConstructors():所有"公有的"构造方法

public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)

2).获取单个的方法,并调用:
public ConstructorgetConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;

3)调用构造方法:
Constructor–>newInstance(Object… initargs)

newInstance是 Constructor类的方法(管理构造函数的类),api的解释为:newInstance(Object… initargs),使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。它的返回值是T类型,所以newInstance是创建了一个构造方法的声明类的新实例对象并为之调用。

反射获取构造方法总结:当我们去获取类构造器时,如果要获取私有方法或私有构造器,则必须使用有 declared 关键字的方法。【当然不止构造器,获取类方法、类属性也是一样使用 declared 关键字的方法】

1.获取构造方法:

1).批量的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
2).获取单个的方法,并调用:
public Constructor getConstructor(Class… parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class… parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
调用构造方法:
Constructor–>newInstance(Object… initargs)

序列化

用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值