Java第2天上午
上午主要讲了下数组及其Arrays工具类
作为一个C++信徒,先来稍微比较下C++和Java数组的小区别:
从语法结构来看,Java中的数组跟C/C++语言中的数组的很相似,是真的哦,呵呵;
But!!!:
Java去掉了C/C++中的可以通过指针来访问元素的功能。这种在C/C++中被普遍接受的功能虽然强大,但是也让Bug横行。Java不支持这种直接通过指针来操纵数据,这类的Bug也被消除了。作为一个被C++复杂特性虐了多次的 单身狗 (什么鬼,情不自禁跑偏了... ) 我想说,Java太好用了。
数组定义时方括号可以放在数据类型后面或者数组名后面。下面的两种Java数组定义格式都是合法的:
type[] arrayName
type arrayName[]
但推荐使用第一种格式
数组是一个引用类型的变量
老师说实际类型的变量和引用类型变量区别:
实际类型的变量声明时就会在内存中开辟空间
引用类型变量在使用时才开辟
数组两种初始化:
//静态初始化
int arr2[]=new int[]{1,2,3,4,5};
String[] array1={"关羽","刘备","张飞"};
//动态初始化
int score[]=new int[3];
String[] array2=new String[]{"hongke","wang"};
查看数组长度:
int length=array1.length;
System.out.println("length:"+array1.length);
遍历数组:
普通循环遍历:
for - each 循环遍历:
他们都打印出:
1
2
3
注意普遍遍历 和 for-each 中的 i 所代表的意义不同
数组下标从0开始 特别注意数组越界异常
做个练习:编写一个程序,产生ArrayIndexOutOfBoundsException异常,并捕获该异常,在控制台输出异常信息。
public class ArrayException {
public static void main(String[] args) {
int[] arr = {1,2};
int i = 0;
try {
while( i < 3 ) {
System.out.println(arr[i]);
i++;
}
}catch(ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
System.out.println("数组越界异常");
}finally {
System.err.println("over");
}
}
}
输出:
over
数组越界异常
课堂上练习了冒泡排序算法:
public class BubbleSort {
public static void main(String[] args) {
int[] a = {3,2,6,7,8,1,22,55,66};
int temp;
for(int i=0;i<a.length-1;++i) {
for(int j=0;j<a.length - i - 1;++j) {
if(a[j] > a[j+1]) {
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
for(int i:a) {
System.out.println(i);
}
}
}
关于更多算法与数据结构请关注我的文集:
C/C++ java 算法与数据结构
(后续我会更新常用算法及数据结构的思想及其C++和Java源码实现)
再后来老师介绍了下Arrays工具类:
Java.util.Arrays类能方便地操作数组,它提供的所有方法都是静态的,下面介绍些功能:
Arrays介绍之对数组排序:(通过sort方法,按升序)
int[] array = {7,8,3,2,12,6,3,5,4};
//对数组的第2个到第6个进行排序进行排序
Arrays.sort(array,2,7);
System.out.println("对数组的第2个到第6个元素进行排序进行排序:Arrays.sort(array,2,7):");
TestArrays.output(array);
//对整个数组进行排序
Arrays.sort(array);
System.out.println("对整个数组进行排序:Arrays.sort(array):");
TestArrays.output(array);
sort更多介绍见Arrays对应的Outline:
Arrays介绍之给数组赋值:(通过fill方法)
int[] array = new int[5];
//填充数组
Arrays.fill(array, 5);
System.out.println("填充数组:Arrays.fill(array, 5):");
TestArrays.output(array);
//将数组的第2和第3个元素赋值为8
Arrays.fill(array, 2, 4, 8);
System.out.println("将数组的第2和第3个元素赋值为8:Arrays.fill(array, 2, 4, 8):");
TestArrays.output(array);
fill 更多介绍见Arrays对应的Outline:
Arrays介绍之查找数组元素:(通过binarySearch方法能对排序好的数组进行二分查找法操作)
int[] array1 = {7,8,3,2,12,6,3,5,4};
Arrays.sort(array1);
System.out.println("元素3在array1中的位置:Arrays.binarySearch(array1, 3):"+"\n"+Arrays.binarySearch(array1, 3));
//如果不存在就返回负数
System.out.println("元素9在array1中的位置:Arrays.binarySearch(array1, 9):"+"\n"+Arrays.binarySearch(array1, 9));
输出:
元素3在array1中的位置:Arrays.binarySearch(array1, 3):
1
元素9在array1中的位置:Arrays.binarySearch(array1, 9):
-9
Arrays介绍之比较数组:(通过equals方法比较数组中元素值是否相等)
int[] array = new int[5];
int[] array1 = {7,8,3,2,12,6,3,5,4};
System.out.println("比较数组元素是否相等:Arrays.equals(array, array1):"+"\n"+Arrays.equals(array, array1));
int[] array2 = array1.clone();
System.out.println("克隆后数组元素是否相等:Arrays.equals(array1, array2):"+"\n"+Arrays.equals(array1, array2));
输出:
比较数组元素是否相等:Arrays.equals(array, array1):
false
克隆后数组元素是否相等:Arrays.equals(array1, array2):
true
比较重点说明:
先来看代码:(尝试自己理解下)
若有不清楚请看下面的解释:
先来了解下数组在内存中的运行机制:
我们知道数组变量属于引用数据类型
数组元素和数组变量在内存里是分开存放的!
数组只是一个引用类型的变量,因此使用它定义一个变量时,仅表示定义了一个引用变量(也就是定义了一个指针) 这个引用变量可以指向任何有效的内存。
只有当该引用指向有效内存后,才可以通过该数组变量来访问数组元素。
引用变量是访问内存中真实对象的根本方式,
也就是说,与所有引用变量相同,如果希望在程序中访问数组对象本身,则只能通过这个数组的引用变量来访问它。
实际的数组对象被存放在堆(heap)内存中,而引用该数组对象的 数组引用变量(要是一个局部变量)被存储在栈(stack)内存中。
即栈内存中的引用变量指向堆内存中的对象!
推荐看一篇:
JAVA 深入数组之 内存中的数组
再来看一下创建数组对象区别:
int[] a = {1,2,3};
int[] b = new int[] {1,2,3};
int[] c = a;
int[] d = a.clone();
首先注意:
int[] a = {1,2,3};
和
int[] b = new int[] {1,2,3};
都是数组的静态初始化方式,int[] a = {1,2,3}; 是 int[] b = new int[] {1,2,3}; 的简化形式。
(另外注意 只有在定义数组的同时执行数组初始化才支持使用简化的静态初始化形式)
int[] a = {1,2,3};
int[] b = new int[] {1,2,3};
后内存中引用指向:
(注意a,b指向不同的堆内存对象)
int[] c = a;
完成的动作是: 在栈中创建c引用变量 c指向 (a指向的对象):
再来看这个
int[] d = a.clone();
先看java doc 文档的说明:
即clone()解释为:返回一个实例(instance)的克隆,即:
创建数组对象说明完成,再来看比较的区别:
首先要知道:原始基本数据类型的变量之间的==与!=所做的是相等性比较——值是否相等,而引用数据类型变量之间的==与!=做的是同一性比较——是否指向同一对象。
所以数组作为引用数据类型 == 判断的是同一性比较(是否指向同一对象)
数组自身的equals() 函数 和 == 一样,也比较 两者是否指向同一对象:
且又因为:
所以前两种比较结果一致:
再来看最后一种比较方式:(Arrays.equals(a,b),即Java8 提供的增强工具类Arrays)
可见Arrays.equals(a,b)比较的是内容相等,若内容一样则返回true
老师还让练习了自己写equals() 函数,要求比较数组内容,并且不考虑数组元素顺序(即认为{1,2,3}和{2,1,3}相等)
下面是我的代码和测试:
public class Test2 {
public static boolean equals(int[] a, int[] b) {
if(a.length != b.length) {
return false;
}else{
BubbleSort(a);
BubbleSort(b);
for(int i=0; i<a.length;++i){
if(a[i] != b[i]) return false;
}
}
return true;
}
public static void BubbleSort(int[] a) {
int temp;
for(int i=0;i<a.length-1;++i) {
for(int j=0;j<a.length - i - 1;++j) {
if(a[j] > a[j+1]) {
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
}
public static void main(String[] args) {
int[] a = {1,2,3};
int[] t = {2,1,3};
System.out.println("自己写的equals函数测试: " + equals(a, t));
}
}
控制台结果:
自己写的equals函数测试: true
拓展:给定一个长字符串a和短字符串b,如何判断短字符串b中所有字符的是否都在长字符串a中?
请参见:字符串包含算法
(素数相乘法可以是一个思路 即把字符串中的字符分别对应到一个唯一标识的素数,而素数们相乘的积又唯一,即利用了素数的数学特性来实现)
下午开讲面向对象:
面向对象是一种解决问题的思想:
注意面向对象的三个特征:
封装、继承和多态
我们通过class来表述一个抽象一个对象:
修饰符有 private public protected :
static关键字:
static使用:
关于匿名对象:
对象的引用:
封装:
this关键字:
注意区别访问修饰符:
构造方法:
来两个IDE干货:
MyEclipse自动生成Getter、Setter和构造方法
最后老师补充了一个递归实现数组全排列问题:
递归 实现数组全排列 Java