(1) 静态导入
导入技术其实在java中是为了方便的使用其他人写好的类。
import java.lang.*|类名
在原来的导包语句中发现只能导入类。如果需要导入的是一些静态的方法或者属性那么就无能为力。
举例1:求一个任意半径的圆形的面积?
// 求一个任意半径的圆形的面积
public static void getArea(){
// 1. 求一个随机的半径
double r = Math.ceil(Math.random()*10);
// 2. 计算面积
double area = 0.0;
area = Math.PI*r*r;
// 3. 打印面积
System.out.println("半径是"+r+"的圆形的面积是:"+area);
}
发现以上的代码中大量的出现了一些静态的成员。
那么可以使用静态导入的方式简化代码的书写。
语法:
import static java.lang.*|静态成员
实战:
importstatic java.lang.Math.PI;
importstatic java.lang.System.out;
importstatic java.lang.Math.random;
importstatic java.lang.Math.ceil;
public class Demo4 {
// 求一个任意半径的圆形的面积
public static void getArea(){
// 1. 求一个随机的半径
double r = ceil(random()*10);
// 2. 计算面积
double area = 0.0;
area = PI*r*r;
// 3. 打印面积
out.println("半径是"+r+"的圆形的面积是:"+area);
}
}
如果代码中使用到了一个类的多个静态成员那么可以直接使用* 进行全部的导入。
import static java.lang.Math.*;
(2) 可变参数
思考:如果开发者现在要定义一个函数(方法),那么不知道参数的个数的时候应该如何指定形参。
语法:定义函数的语法
修饰符 返回值类型 方法名(参数类型… 变量名 ) 异常的声明{
// 函数体
return;
}
注:学习可变参数的本质
- 可变参数其实是一个可变的数组
- 可变参数在方法的声明中只能出现在参数列表的最后一个位置
- 可变参数只能在参数列表中出现一次
举例1:求任意个整数的累加和?
// 求任意个整数的累加和?
public static long getSum(int... is){
long sum = 0;
for (int i = 0; i < is.length; i++) {
sum +=is[i];
}
return sum;
}
举例2:SUN的API中用的可变参数。
static <T> List<T> asList(T... a) 返回一个受指定数组支持的固定大小的列表。
u 包装类
其实在java中有四型八种的基本数据类型。如果所有的基本数据类型不是对象的话那么java
语言就不是正真的OOP语言。
Wrapper Class即包装类。在包装类中SUN封转了开发者常用的一些属性和方法,可以进行快速的编程。
包装类 |
基本数据类型 |
Byte |
byte |
Short |
short |
Integer |
int |
Long |
long |
Boolean |
boolean |
Character |
char |
Float |
float |
Double |
double |
举例1:体验Integer类提供的属性。
// 体验Integr类的属性
public static void getField() {
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Integer.MAX_VALUE); // 2147483647
}
阅读以下的代码,分析代码的错误原因:
long date = 12345678910; // 报错
12345678910
2147483647
举例2:体验Integer类提供的方法。
主要学习的是整数到字符串之间的转换的方法。
// 体验Integr类的方法
public static void getMethod() {
// 创建类对象
Integer in1 = new Integer(123);
int i1 = in1.intValue();
System.out.println(i1+1);
// 转换为字符串
String str1 = in1.toString();
System.out.println(str1+1);
}
其实在这里没有必要转型为String的时候进行基本的toString()调用。
简化以上的代码:
// 体验Integr类的方法
public static void getMethod2() {
// 创建类对象
Integer in1 = new Integer(123);
int i1 = in1; // 自动拆箱
System.out.println(i1+1);
// 转换为字符串
System.out.println(in1+""+1);
}
(3)什么是自动拆箱和自动装箱?
自动装箱: 如果将基本类型传递给包装类型。 Integer in1 = 12;
自动拆箱: 如果将包装类型传递给基本类型。 int i1 = in1
在泛型的时候比较有用:
集合:主要的用途是进行对象的存储。
list.add(1); //自动装箱
思考:String str = “hello”;
u 增强for循环
如果要遍历一个指定的数,那么我们一般要使用传统的的for循环。
语法:
for( 条件的初始化语句; 条件表达式; 循环的增量 ){
// 循环体 break或continue
}
这样写的话每次都会遇到一个下标越界的一个异常。
因此可以使用增强for循环进行快速的遍历(数组、集合以及实现了Iterable接口的类)。
语法:
for(数据类型 变量名:需要遍历的集合){
// 循环体
}
举例1:遍历一个普通的数组。
// 遍历一个数组
public static void printArray(int [] a){
for(int temp:a){
System.out.println(temp);
}
}
举例2:遍历一个List集合。
// 遍历一个list
public static void printList(List<String> list){
for (String string : list) {
System.out.println(string);
}
}
举例3:遍历一个Map集合。
// 遍历一个Map集合
public static void printMap(Map<Integer,String> map){
// 想将其转换为实现了Iterable接口的Set类
Set<Map.Entry<Integer, String>> set = map.entrySet();
// 遍历set集合
for(Map.Entry<Integer, String> entry:set){
// 获取entry对象的key和value值
Integer key = entry.getKey();
String value = entry.getValue();
System.out.println(key+"="+value+",");
}
}
思考:如果以上的集合没有使用泛型,那么在使用for循环的时候应该使用什么类型接收集合数据? Object
问题1:使用增强for循环是否可以改变集合中数据?
因为for循环在遍历的时候使用的是将值拷贝一份给临时变量。因此改变临时变量不会改变集合中的数据值。
问题2:使用增强for循环遍历集合的时候操作集合的问题?
// 遍历一个list
public static void printList(List<String> list){
for (String string : list) {
list.add("eeee"); // 运行错误
System.out.println(string);
}
System.out.println("遍历中: "+list);
}
异常信息如下:
Exception in thread "main" java.util.ConcurrentModificationException
模拟基础班看过的场景:
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("aaaa");
list.add("bbbb");
list.add("cccc");
list.add("dddd");
Iterator<String> it = list.iterator();
while(it.hasNext()){
list.add("yyyy");
String str = it.next();
System.out.println(str);
}
}
运行异常:
Exception in thread "main" java.util.ConcurrentModificationException
总结;
在使用增强for循环进行集合的迭代的时候其实默认使用的是迭代器,因此在循环中不能使用集合的引用变量直接操作集合,避免导致多线程并发访问的安全性异常。
u 安全的枚举类
在实际的项目的开发中我们经常需要一类数据,这一类数据的值是特定范围的一组值。如:
性别:[男、女]
交通灯:[红、黄、绿]
星期几:[一~七]
以上的一组值可以定义为枚举数据类型。
语法:
修饰符 enum 枚举类名{
// 定义枚举的一组值,多个值之间使用逗号进行分隔
}
实现:
public enum Gender {
MALE,FEMALE;
}
问题:枚举的本质是什么?
- 枚举本质是一个类
- 默认继承自Enum类
- 枚举值本质是枚举类的静态常量值
- 枚举值都在静态代码块中进行初始化
- 枚举类的默认构造函数式有参数的且只能私有
- 枚举是单例模式
- 既然枚举是一个普通类,那么我们开发人员就可以在类中定义类的成员(属性、构造函数、函数)。
举例1:在枚举中定义属性。
public enum TrafficLight {
// 定义枚举值
RED,GREEN,YELLOW;
// 定义成员属性
public String info = "交通灯信息";
public static void main(String[] args) {
System.out.println(TrafficLight.GREEN.info);
}
}
举例2::在枚举中定义构造函数。
public enum TrafficLight {
// 定义枚举值
RED("红灯"),GREEN("绿灯"),YELLOW("黄灯");
// 定义成员属性
public String info = "交通灯信息";
// 提供构造函数进行属性的初始化
private TrafficLight(String info){
this.info = info;
}
public static void main(String[] args) {
System.out.println(TrafficLight.GREEN.info);
System.out.println(TrafficLight.RED.info);
System.out.println(TrafficLight.YELLOW.info);
}
}
切记的是为了保证枚举是单例的那么构造函数全部要私有。
举例3:在枚举中定义函数。
public enum TrafficLight {
// 定义枚举值
RED("红灯") {
@Override
public void showMessage() {
System.out.println("红灯停!");
}
},
GREEN("绿灯") {
@Override
public void showMessage() {
System.out.println("绿灯行!");
}
},
YELLOW("黄灯") {
@Override
public void showMessage() {
System.out.println("你自己看着办!");
}
};
// 定义成员属性
public String info = "交通灯信息";
// 提供构造函数进行属性的初始化
private TrafficLight(String info) {
this.info = info;
}
// 提供一个表明灯的信息的方法
public abstract void showMessage();
public static void main(String[] args) {
System.out.println(TrafficLight.GREEN.info);
System.out.println(TrafficLight.RED.info);
System.out.println(TrafficLight.YELLOW.info);
TrafficLight.RED.showMessage();
}
}
以上的代码可见在枚举类中可以定义抽象方法,但是不能将枚举类声明为抽象类,只能在声明枚举值的时候实现所有的抽象方法即(匿名内部类)。
在实际的枚举中其实自定义的枚举类默认继承Enum类,那么我们的枚举类中就会有Enum类中的定义好的属性和方法。
常用方法
方法的描述
String name()
获取枚举值的名称
int ordinal()
返回枚举值定义的序号
valueOf(Class<T> enumType, String name)
通过反射查找指定的类中的指定名的枚举值
values()
该方法在API中不可见但是可用举例3:使用Enum类中常用的方法。
// 常用的方法体验
System.out.println(TrafficLight.YELLOW.name()); // YELLOW
System.out.println(TrafficLight.RED.ordinal()); // 0
System.out.println(TrafficLight.valueOf(TrafficLight.class,"GREEN"));
以上的方法都是在API中可见的方法,但是有一些方法是API中不可见但是内部其实定义了的方法。
举例4:遍历枚举值。
// 遍历枚举值
TrafficLight [] trans = TrafficLight.values();
for(TrafficLight temp:trans){
System.out.println(temp);
}