文档库 最新最全的文档下载
当前位置:文档库 › Java 快速入门练习

Java 快速入门练习

Java 快速入门练习
Java 快速入门练习

第5章实验–数组

5.1实验目标

(1)理解在Java中如何声明、分配和使用(多维)数组

(2)学习数组排序和查找的基本算法

(3)了解JA V A Reflection API 和其他常用类

5.2实验说明

本章实验教程将介绍数组(array)的使用,学习Java数组相关的类Array和Arrays。简单介绍Java反射(Reflection)的用法。

以下的实验包括4种类型,每种类型都用括号里面的字母表示:

D - 例程,表示这是一个例子, 要求练习者阅读指南和代码;

I - 交互式练习, 练习者完成实验指定的简单任务,如修改部分代码, 观察程序运行时的变化等;

W - 热身练习,练习者的编程工作量逐渐加大。

P - 完整编程,要求练习者根据要求,完成完整的JA V A程序。

5.3实验准备

从本实验教程光盘中拷贝Lab05文件目录到本地磁盘, 如D: 盘。Lab05文件目录中将包含本次实验所需的所有资料。Lab05的相关资料也可以从本实验教程的网站下载:http://javaLab/lab05.zip

将Lab04中的MathUtility.java(程序清单4-6)程序拷贝到Lab05目录下。

5.4实验任务

实验5.4.1: (D)数组的基本概念

Java变量(variable)可以存储程序的数据,每个变量有标识、类型和作用域。使用同种类型和作用域的多个数据时,我们通常把这些数据存放在一个数据结构而不是单个的变量中。最常见的数据结构是数组(array)。一个数组中能够存储的数据个数是固定的,并且存放的数据类型相同。尽管数组是一个对象,但是数组的用法与基本数据类型相似。

图5.1可以帮助我们理解数组的结构。

图5.1 长度为8的数组

这是一个有8个元素的数组,数组中的每个元素有各自的值。图中每个元素上方的数字表明了元素的索引(index)。数组中的元素总是使用索引引用的。第一个元素的索引总是为0。重复,第一个元素的索引总是为0,而最后一个元素的索引总是“数组长度-1”。上图的数组中,最后一个元素的索引是8-1 = 7。

我们可以创建任何数据类型的数组。下面来看一个整型数组的例子。

编译并运行ExamScoresl.java,输入0到100之间的一组整数为命令行参数。假设输入的这组整数就是考试成绩,这个程序将显示原始成绩和调整后的成绩。成绩调整的规则是:将最高成绩上调到100分,计算调整的幅度,再根据幅度相应调整其他成绩。

程序清单5-1:ExamScores1.java

// Given a sequence of exam scores as

// command-line arguments, displays table

// of exam scores and curved scores.

public class ExamScores1 {

public static void main(String[] commandLineArgs)

{

if ( commandLineArgs.length == 0 ) {

System.out.print("Given a sequence of exam scores ");

System.out.println("entered as command line arguments,");

System.out.print("this program will curve them up ");

System.out.println("by raising the highest to 100 and ");

System.out.println("raising all others by the same amount.");

System.exit(0);

} // if no command-line arguments

// Named constant for width of displayed columns:

final int columnWidth = 5;

// Named constant for the number of scores:

final int numberOfScores = commandLineArgs.length;

// Declare reference to array

// which will store exam scores:

int[] scores;

// Instantiate (create) the array itself,

// i.e. allocate space to store the exam scores:

scores = new int[numberOfScores];

// Read scores into array and determine maximum:

int maximumScore = 0;

for ( int i = 0; i < scores.length; i++ ) {

scores[i] = Integer.parseInt(commandLineArgs[i]);

maximumScore = Math.max(maximumScore, scores[i]);

} // for i

// Determine how many points to curve up all scores:

int curveUp = 100 - maximumScore;

// Output table of original scores and curved scores

for ( int i = 0; i < scores.length; i++ ) {

// Print original score in a right-justified column:

String scoreText = Integer.toString(scores[i]);

for ( int j = scoreText.length(); j < columnWidth; j++ )

System.out.print(" ");

System.out.print(scoreText);

// Calculate curved score;

int curvedScore = scores[i] + curveUp;

// Print curved score in a right-justified column;

String curvedScoreText = Integer.toString(curvedScore);

for ( int k = curvedScoreText.length(); k < columnWidth; k++ )

System.out.print(" ");

System.out.println(curvedScoreText);

} // for i

} // method main(String[])

} // class ExamScores1

大家可能已经发现,ExamScoresl.java源代码中main方法的命令行参数数组的名字与惯常不同,这里使用了commandLineArgs。其实使用什么名字作为命令行参数的数组名并没有关系,只要这个名字在整个main方法中保持一致就行。在一个具体的程序中,我们通常把命令行参数数组取名为args,把命令行参数个数的变量取名为argv,命令行参数数组是一个字符串数组。

ExamScoresl.java程序中需要跟踪所有的成绩,因此将考试成绩存放在一个int型数组中。创建数组的三个步骤是:(1)声明一个数组引用变量;(2)实例化(创建)数组本身,也就是为数组分配内存空间;(3)初始化数组中的每个变量。

1.数组的声明

数组变量的声明和其他Java变量的声明类似,声明数组的语法模板:

DataType ArrayName [ConstIntExpression];

DataType [ConstIntExpression] ArrayName;

DataType是数据类型,即数组中元素的数据类型;ArrayName是合法的变量;[ ]符号中的ConsIntExpression指明数组的大小,即数组中元素的个数。

程序ExamScoresl.java中,声明int数组变量:

int [] scores;

另外一种声明数组的方式:

int scores[];

这两种数组声明方式在语法上都是正确的,都能被编译器接受。编者个人喜欢第一种(int[] scores)声明方式,因为它更清晰地说明了数组变量的名字是scores,而不是scores[];scores被声明为一个指向整型数组的指针。然而,更普遍使用的是第二种方式,尤其在Java官方文档中更为明显,因为这种方式与C++中的声明方式比较接近。

2.实例化数组

实例化scores数组的语句如下:

scores = new int[numberOfScores];

实例化数组,即为数组元素分配内存空间,是通过new操作符实现的。new操作符后是数据类型以及元素个数。元素个数放在[]运算符中。下面是一些例子:

counts = new int[5];

names = new String[100];

3.数组元素的初始化

将scores数组中的元素在循环中初始化的语句如下:

for ( int i = 0; i < scores.length; i++ ) {

scores[i] = Integer.parseInt(commandLineArgs[i]);

scores.length是数组元素的个数,就象commandLineArgs.length是数组commandLineArgs的元素个数一样。数组元素的范围从0到length - 1。

4.数组声明、实例化和初始化的更多解释

声明和实例化数组的常见形式如下例所示:

int[] scores;

scores = new int[numberOfScores];

声明和实例化数组可以合并成一个语句:

int[] scores = new int[numberOfScores];

还可以定义初始化列表(Initializer List)来初始化数组元素:

int[] numbers = {4, 3, 2, 1};

String[] name = {"Zhang", "Wang", "Li"};

数组的长度是由{}中的元素个数隐含定义的,numbers数组的长度为4,name数组的长度为3。当

数组的声明和创建分开时,仍然可以使用初始化列表,只是这种方式不太简练:int[] numbers;

numbers = new int[]{4, 3, 2, 1};

再次强调一下,数组变量是一个内存位置的名字,这个内存位置存储的不是数组本身,而是数组在内存中存放的地址。因此,数组变量存放了一个指向数组的指针。当数组变量第一次声明时,它并没有真正指向一个数组。数组声明只是开辟一个存放指针的空间。之后,当使用关键字new实例化数组并将其指定给一个数组变量时,该数组变量就存放了一个指向数组的指针。

范例5-1程序的顶端有这样一个声明:

final int columnWidth = 5;

这个声明看上去象一个变量的声明,不同的是在最前面有一个关键字final。关键字final意味着columnWidth被声明为一个常量。常量的值在第一次初始化之后就不能改变。

为什么要费心去定义常量,而不在代码中直接使用常量的值呢?原因在于方便程序员修改程序,程序员只需查看代码顶端并修改常量的值,而不需要修改该常量的值出现的每行代码。

实验5.4.2: (I)访问数组元素

引用数组中的元素,使用[ ] 操作符。范例5-1中,访问scores数组元素:

int score = scores[0]; // 得到第一个元素

int score = scores[3]; // 得到第四个元素

[ ]中的索引可以是整数,或者整型变量。索引的取值范围在0到数组元素个数-1之间。数组变量与数组中索引变量的区别在于,数组变量代表整个数组,数组中的索引变量代表了数组中的元素在数组中的位置。

通常我们会使用for循环语句来操作数组元素,见范例5-2。

程序清单5-2:AccessArrayWithForLoop.java

public class AccessArrayWithForLoop {

public static void main(String[] args) {

String[] months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",

"July", "Aug", "Sep", "Oct", "Nov", "Dec"};

int[] sizes = {31,28,31,30,31,30,31,31,30,31,30,31};

for(int i = 0; i < months.length; i++ ) {

System.out.println(months[i] + " has " + sizes[i] + " days.");

}

}

}

注意for循环中的变量i,i的取值在0到months.length-1之间。试着把源代码

for(int i = 0; i < months.length; i++ )

改成:

for(int i = 0; i < = months.length; i++ )

重新编译、运行程序。回答下面的问题:

代码可以正常编译吗?为什么?

___________________________________________________________

程序可以正常执行吗?为什么?

___________________________________________________________

实验5.4.3: (I)查找最大数

GreatestNumber.java(范例5-3)将对话框输入的3个数字保存在数组中,计算出其中的最大值。

程序清单5-3:GreatestNumber.java

import javax.swing.JOptionPane;

public class GreatestNumber {

public static void main(String[] args) {

int[] num = new int[10];

int counter;

int max = 0;

int totalnumber = 3;

// Prompt a user to enter numbers

for(counter = 0; counter < totalnumber; counter++) {

num[counter] = Integer.parseInt ( JOptionPane.showInputDialog (

"Enter numbers until " + totalnumber + " numbers are entered"));

// Compute the greatest number up to this point

if((counter == 0)||(num[counter] > max))

max = num[counter];

}

// Display the greatest number.

JOptionPane.showMessageDialog(null,

"The number with the greatest value is " + max);

}

}

现在,参照GreatestNumber.java写一个新的程序SmallestNumber.java, 找出3个数中的最小值。实验5.4.4: (W)练习使用数组

写一个类似于ExamScores1.java的程序ExamScores2.java,从命令行参数输入学生成绩,没有输入命令行参数时,程序会显示提示信息。要求程序输出成绩列表,以及成绩的最高分和最低分。程序

中不使用Math类的max和min方法。

实验5.4.5: (P)用数组实现斐波纳契函数

编写程序FibonacciArray.java,用数组实现斐波纳契函数。由键盘读入n值(参见实验1.4.15)。程序将在控制台输出此斐波纳契序列f(0),f(1),…… f(n)。

斐波纳契序列的定义如下:

如果n = 0 或者n = 1 , 则f(n) = 1

如果n是一个整数并且n > 1 , 则f(n)= f(n-1) + f(n-2)

实验5.4.6: (I)字符串和字符数组

在Java库文件中查看String类的toCharArray方法。我们提到过String包含一串字符,更准确地讲,包含了一个字符数组以及操作这些字符的大量方法。

String类的toCharArray方法将字符串转换为Character数组。toCharArray是一个实例方法还是类方法,查看Java文档,写下结果:

_______________________________________________________

范例5-3使用toCharArray方法实现字符串反转。

程序清单5-3:StringReverse.java

public class StringReverse {

public static void main(String[] args) {

System.out.println(reverse(args[0]));

}

public static String reverse( String inputString) {

if (inputString == null)

return null;

else {

char[] charArray = inputString.toCharArray(); //string to char array

for (int i = 0; i < charArray.length / 2; i++) {

char temp = charArray [i];

charArray [i] = charArray [charArray.length - i - 1];

charArray [charArray.length - i - 1] = temp;

}

String re = new String(charArray); //char array to string

return re;

}

} // method reverse

}

以上程序的算法如下图所示,程序进行1/2数组长度次的循环,每次调换头尾两个位置中的元素。在第一次循环中,先将位置0上的元素存放在temp变量,然后将位置9上的元素赋值到位置0,最后将temp中元素存入位置9。在第二次循环时,先将位置1上的元素存放在temp变量,然后将位置8上的元素赋值到位置1,最后将temp中元素存入位置8。依次类推,最后一次循环,将位置4和位置5中的元素交换。

图5.2 字符串反转算法描述

实验5.4.7: (I)传递数组参数

用简单类型数据做参数时,Java遵循值传递的原则。实质上,就是将参数值先拷贝一份,然后将拷贝传递给方法。因此,在方法内部修改参数对原来的变量没有影响(因为只是对拷贝的修改),而且,方法返回时,方法调用的空间回收,拷贝的参数空间也被收回。

Java中,不能把对象传递给方法,只能传递对象的引用(Reference,即对象的内存地址)。引用本身也是采用值调用。当一个方法接受对象的引用后,它就可以直接操纵对象。

尽管数组在语法上有别于其他一般意义上的对象,但数组被Java看作是对象。数组以引用调用的方式传递给方法,数组的引用变量包含一个指针,指向数组在存储器中的实际存储位置。

编译并运行程序ValueVsReference.java。

程序清单5-4:V alueVsReference.java

public class ValueVsReference {

public static void main(String[] args) {

short[] a = { 0, 2, 4, 6, 8 };

System.out.println("The values originally stored in the array are:");

for ( int i = 0; i < a.length; i++ )

System.out.print(" " + a[i]);

System.out.println();

System.out.println("Let's see how the values change.");

modifyPrimitive(a[0]);

for ( int i = 0; i < a.length; i++ )

System.out.print(" " + a[i]);

System.out.println(" Method tried to modify primitive element.");

modifyArray(a);

for ( int i = 0; i < a.length; i++ )

System.out.print(" " + a[i]);

System.out.println(" Method modified array.");

modifyArrayReference(a);

for ( int i = 0; i < a.length; i++ )

System.out.print(" " + a[i]);

System.out.println(" Method modified its own reference to array.");

} // method main

public static void modifyPrimitive(short p) {

p = 20;

} // method methodA

public static void modifyArray(short[] b) {

for ( int j = 0; j < b.length; j++ )

b[j] = (short) (j*(-3));

} // method modifyArray

public static void modifyArrayReference(short[] b) {

b = new short[5];

for ( int j = 0; j < b.length; j++ )

b[j] = (short) (j*3);

} // method modifyArrayReference

} // class ValueVsReference

范例5-4定义了main和其他三个方法modifyPrimitive,、modifyArray和modifyArrayReference。

(1)modifyPrimitive 方法修改参数p的值,p是short原始数据类型。因此,此方法的参数转递为值传递。main方法中调用modifyPrimitive方法,传递的实际参数是数组的一个元素a[0],此元素的类型也是short原始数据类型。

(2)modifyArray方法的参数为数组引用变量b,而不是单独的某个数组元素。方法的头部定义如下:

public static void modifyArray(short[] b)

通过引用变量b,可以操纵b指向的数组对象。main方法中调用modifyArray方法,传递的实际参数是数组引用变量a,此时a和b的实际值都是一个指向同一数组对象的指针。modifyArray 方法中,对b引用的数组对象的修改,就是对a引用的数组对象的修改。方法调用完成后,变量b的空间被回收,a引用的数组对象被修改。

(3)modifyArrayReference 方法内,数组引用变量b 被重新赋值,指向一个新创建的数组:

b = new short[5];

main方法中调用modifyArrayReference方法,传递的实际参数是数组引用变量a。但由于上面的这个赋值语句,形式参数b指向了一个新的数组,而不再指向a引用的数组。对变量b引用

的数组对象的任何修改都不会改变变量a引用的数组对象。

现在,请写下程序执行后的结果,并认真思考为什么是这样的结果。

___________________________________________________________________________________ ___________________________________________________________________________________ ___________________________________________________________________________________ ___________________________________________________________________________________ 实验5.4.8: (W)写一个带有数组参数的方法

在MathUtility.java(见程序清单4-6)中,写一个静态方法average,此方法用一个双精度浮点数(double)数组作为参数,并返回此数组中元素的平均值。如果数组长度为0,方法返回值为0,并打印一个标准错误输出流消息。回顾如何定义一个指向double类型数组的指针,并在方法的参数列表中声明。

以如下方式定义average方法的方法头:

public static double average (double[] doubleArray)

运行AverageTest.java程序测试average方法。

程序清单5-5:AverageTest

public class AverageTest {

public static void main(String[] args) {

if (args.length == 0) {

System.out.println("This program will average any "

+ "number of precision floating-point ");

System.out.println("numbers entered as command-line "

+ "arguments. Result should be zero");

System.out.println("for no command-line arguments.");

} // if

double[] numbers = new double[args.length];

for ( int i = 0; i < args.length; i++ )

numbers[i] = new Double(args[i]).doubleValue();

System.out.println("The average is " + MathUtility.average(numbers) + ".");

} // method main

} // class AverageTest

实验5.4.9: (P)写一个返回值为数组的方法

一个方法如果没有返回值,则在该方法的前面用void关键字来修饰;如果返回值的类型为基本数据类型,只需在声明方法的前面加上相应的数据类型即可。同理,若方法需返回一个数组,则必须在该方法的前面加上数组类型的修饰符。例如,方法返回一个整形数组,则在该方法前加上int[ ]。

在MathUtility.java(见程序清单4-6)中,写一个power方法,计算一组数的指数。计算结果以数组的方式返回,这个方法应该有如下的方法头:

public static double[] power(float[] base, int exponent)

要求作为参数传递进来的数组不被改变。提示:在power方法内部,创建了一个新的数组并把base的内容拷贝到其中。然后对新数组进行操作,而不是修改旧的数组,旧的数组被完整地保留下来。

执行程序PowerTest4.java来测试该方法。

程序清单5-6:PowerTest4.java

public class PowerTest4 {

public static void main(String[] args) {

System.out.print("This program will raise the float ");

System.out.println("numbers in an array to an integer power.");

float[] basesToTest = { 1, 2, 3, 4};

testPower(basesToTest, 2);

testPower(basesToTest, 3);

testPower(basesToTest, -2);

testPower(basesToTest, 0);

} // method main(String[])

public static void testPower(float[] base, int exponent)

{

System.out.println();

System.out.print("Raising the numbers in ");

printArray(base);

System.out.println(" to the " + exponent + " power:");

double[] result = MathUtility.power(base, exponent);

System.out.print(" The numbers in ");

printArray(base);

System.out.println(" to the " + exponent + " power are:");

System.out.print(" ");

printArray(result);

} // method testPower

public static void printArray(double[] numbers) {

System.out.print("{");

if ( numbers.length > 0 )

System.out.print(" " + numbers[0]);

for ( int i = 1; i < numbers.length; i++ )

System.out.print(", " + numbers[i]);

System.out.print(" }");

} // method printArray(double[])

} // class PowerTest4

实验5.4.10: (P)简单的数组中的查找

在数组中查找某个元素,一种简单的方法是顺序查找法(Linear Search),即,从数组的第一个记录开始,逐个进行数组中元素和给定值的比较。

写一个LinearSearch.java程序查找一个字符串中包含多少个指定字符,这个字符串和指定字符由键盘输入。要求输出此字符串中指定字符的位置,及字符总数。

实验5.4.11: (D)多维数组

1.Java语言中,多维数组(Multi-dimensional arrays)被看作是数组的数组。

二维数组可以被想象成一个二维的表,表里的所有元素有统一的数据类型。

一个int类型的二维数组声明如下:

int a[ ][ ];

int[ ][ ] a;

二维数组的初始化有两种方式:静态初始化和动态初始化。

(1)静态初始化

a[ ][ ]={{1,2},{3,4},{5,6,7}};

图5.3 静态初始化一个二维数组a

Java语言中,不要求多维数组每一维的大小相同。

(2)动态初始化

int[ ][ ] b = new int[2][3];

这种方式直接为每一维分配空间,因为是int类型数组,数组中的元素被初始化成0。

图5.4 动态初始化一个2行(rows)3列(columns)的二维数组b

下面的语句同样实现了数组的初始化:

int b[ ][ ] = new int[2][ ];

b[0] = new int[3];

b[1] = new int[3];

二维数组元素的引用方式为:b[1][2] = 5;

图5.5二维数组元素的引用

2.编译、运行MultiDimArray.java程序,理解其中各种多维数组的创建:

程序清单5-7:MultiDimArray.java

import java.util.*;

public class MultiDimArray {

static Random rand = new Random();

static int pRand(int mod) {//产生1~mod之间的随机数

return Math.abs(rand.nextInt()) % mod + 1;

}

public static void main(String[] args) {

int[][] a1 = {//声明2维数组al,并初始化

{ 1, 2, 3, },

{ 4, 5, 6, },

};

for(int i = 0; i < a1.length; i++)//输出数组al

for(int j = 0; j < a1[i].length; j++)

prt("a1[" + i + "][" + j +"] = " + a1[i][j]);

// 声明三维数组a2,分配固定的空间:

int[][][] a2 = new int[2][2][4];

for(int i = 0; i < a2.length; i++)//输出a2中元素

for(int j = 0; j < a2[i].length; j++)

for(int k = 0; k < a2[i][j].length;

k++)

prt("a2[" + i + "][" +j + "][" + k +"] = " + a2[i][j][k]);

// 任意长度的三维数组:

int[][][] a3 = new int[pRand(7)][][];//指定第一维的大小为1~7的随机数

for(int i = 0; i < a3.length; i++) {

a3[i] = new int[pRand(5)][];//指定第二维大小

for(int j = 0; j < a3[i].length; j++)

a3[i][j] = new int[pRand(5)];//指定第三维大小

}

for(int i = 0; i < a3.length; i++)//输出a3中元素

for(int j = 0; j < a3[i].length; j++)

for(int k = 0; k < a3[i][j].length;

k++)

prt("a3[" + i + "][" +j + "][" + k +"] = " + a3[i][j][k]);

// 非基本类型的三维数组:

Integer[][] a4 = {

{ new Integer(1), new Integer(2)},

{ new Integer(3), new Integer(4)},

{ new Integer(5), new Integer(6)},

};

for(int i = 0; i < a4.length; i++)

for(int j = 0; j < a4[i].length; j++)

prt("a4[" + i + "][" + j +"] = " + a4[i][j]);

Integer[][] a5;

a5 = new Integer[3][];

for(int i = 0; i < a5.length; i++) {

a5[i] = new Integer[3];

for(int j = 0; j < a5[i].length; j++)

a5[i][j] = new Integer(i*j);

}

for(int i = 0; i < a5.length; i++)

for(int j = 0; j < a5[i].length; j++)

prt("a5[" + i + "][" + j +"] = " + a5[i][j]);

}

static void prt(String s) {

System.out.println(s);

}

}

实验5.4.12: (P)练习使用多维数组

写一个Matrix.java程序实现两个3×3的整数矩阵相乘,并将其结果打印到屏幕上,运算过程中要用到嵌套循环及+=这样的复合运算符号,并用“\t”调整输出的格式。

int[][] matrixA = { { 1, 0, 1 },

{ 1, 2, 3 },

{ 1, 4, 5 } };

int[][] matrixB = { { 5, 4, 0 },

{ 4, 8, 1 },

{ 1, 1, 0 } };

提示:在写程序之前,仔细分析矩阵相乘的原理,并将matrixA x matrixB的计算结果写在下面,便于纠正程序设计思路。

int[][] matrixAB =

实验5.4.13: (D)int数组的冒泡排序

在程序中,经常需要将数组中的数据排序。排序对象要能够相互比较,这是排序的前提。范例5-8是对int数组进行冒泡排序的示例。

冒泡排序的基本思想:

设想被排序的数组R[1..N]垂直竖立,将每个数据元素看作有重量的气泡,根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡扫描到违反本原则的轻气泡,就使其向上"漂浮",如此反复进行,直至最后任何两个气泡都是轻者在上,重者在下为止。

算法示例:以升序排列int数组{3,6,2,1,5,4,8,7}。依次比较相邻的两个数,将小数放在前面,大数放在后面。首先比较数组的倒数第1个和倒数第2个数,将小数放前,大数放后,即7放前,8放后;然后比较倒数第2个数和倒数第3个数,4放前,7放后;如此继续,4放前,5放后;1放前,4放后;1放前,2放后;1放前,6放后;1放前,3放后;此时第一轮结束,在最前面的数一定为所有数中的最小数。重复以上过程,仍从倒数第1个和倒数第2个数开始比较(因为可能由于倒数第2个数和倒数第3个数的交换,使得倒数第1个数不再大于倒数第2个数),将小数放前,大数放后,一直比较到最小数后的一对相邻数,将小数放前,大数放后,第二轮结束,在第二个数中得到一个新的最小数。如此下去,直至最终完成排序。

31111111

63222222

26333333

12644444

54465555

45556666

87777777

78888888

图5.7 冒泡排序(Bubble Sort)算法示例

程序清单5-8:Int BubbleSort.java

// IntBubbleSort.java

public class IntBubbleSort {

private int[] testArray={3,6,2,1,5,4,8,7};//声明并初始化数组

public static void main(String[] args) {

IntBubbleSort ibs = new IntBubbleSort();

for(int i=0;i

System.out.println(ibs.testArray[i]);

} // 输出原始的数组

ibs.sort();//调用排序方法

System.out.println("排序后的输出");

for(int i=0;i

System.out.println(ibs.testArray[i]);

}

}

public void sort(){

for(int i = 1;i < testArray.length; i++){

for(int j = testArray.length-1;j >= i; j--)

if(testArray[j] < testArray[j-1]) {

int temp = testArray[j-1];

testArray[j-1]= testArray[j];

testArray[j]= temp;

}

}

}

}

testArray是一个int数组引用变量,它是一个实例变量,其作用域为整个实例。testArray有一个private修饰符,表明这是一个私有变量,只能在类内部访问。

注意这里的sort方法,由于它不是静态方法,调用的形式为:

对象引用.方法(参数)

范例5-8中,首先调用构造方法创建了一个IntBubbleSort实例ibs:

IntBubbleSort ibs = new IntBubbleSort();

再由ibs调用sort方法:

ibs.sort(); //调用排序方法

冒泡算法是由双重for循环具体实现的,具体见sort方法中的代码。

实验5.4.14: (P)int数组的选择排序

模仿范例5-8写一个IntSelectionSort.java程序,采用选择排序(Selection Sort)算法实现int数组的排序。选择排序法是一个很简单的算法。其原理是首先找到数据清单中的最小的数据,然后将这个数据同第一个数据交换位置;接下来找第二小的数据,再将其同第二个数据交换位置,以此类推。

算法示例:

31111111

66222222

22633333

13364444

55555555

44446666

88888887

77777778

图5.8 选择排序(Selection Sort)算法说明

实验5.4.15: (I)数组的复制

如何将整个数组的值复制给另一个数组呢?或许会用如下语句:

double[] b = a;

来实现将数组a的内容拷贝到数组b中,虽然这是有效的代码,但并不能得到我们想要的结果。为了能够复制一个数组,要用for循环对数组中的每一个元素都进行操作。见如下的代码片断:

// 创建一个和数组a相同长度的数组b

double[] b = new double[a.length];

// 设定数组b中每个元素的值等于数组a中每个元素的值

for (int i=0; i

b[i] = a[i];

}

范例5-9示范了进行数组复制的方法,预测其运行结果:

_____________________________________________________________________________

程序清单5-9:ArrayCopy.java

import java.io.*;

public class ArrayCopy {

public static void main(String[] argv) {

// create a new integer array

int N = 12; // length of array

int[] array1 = new int[N];

System.out.print("array1 = ");

// assign some arbitrary values to the array elements

for (int i=0; i

array1[i] = i*i;

}

// print the array

for (int i=0; i

System.out.print(array1[i] + " ");

}

System.out.println("");

// Create a copy (?) of array1 and print it out

System.out.print("array2 = ");

int[] array2 = array1; // "copy" the array in one go

for (int i=0; i

System.out.print(array2[i] + " ");

}

System.out.println("");

// Create a copy (?) of array1 individual elements and print it out

System.out.print("array3 = ");

int[] array3 = new int[array1.length];

for (int i=0; i

array3[i] = array1[i]; // copy element by element

System.out.print(array3[i] + " "); // print new array

}

System.out.println("");

// Modify an element of array1 and see what else changes.

System.out.println("Changing array1[3] to 999 ...");

array1[3] = 999;

System.out.println("array1[3] = " + array1[3]);

System.out.println("array2[3] = " + array2[3]);

System.out.println("array3[3] = " + array3[3]);

}

} // ArrayCopy.java

编译,运行范例5-9,比较程序运行结果是否和预测输出相同。若相同,说明对数组的理解比较到位,否则,仔细阅读下面的解释。

数组间赋值语句:

Java中,对于基本数据类型变量,double b = a 实现的是将a的值赋给b。数组则不同,b = a的含义是b和a引用的是同一个数组,因此对b的一系列操作等同于对a的。数组是引用数据类型,也就是说他们是按引用处理的;而int、double、boolean这些原始数据类型,是按值处理的。例如,int[] list={1,2,3}中的数组{1,2,3}是放在计算机内存的某个地方的,用“=”运算符将数组对象指定给数组引用变量list。

注意,用new创建的对象,包括数组,都是引用数据类型。图5.8说明了使用数组间赋值语句的结果。先定义数组a,再将a赋值给数组b,其结果是它们会指向同一组数据,b并没有创建和a 一样的副本。

图5.9 数组间赋值语句

数组的比较:

注意,不可以用==来比较两个数组的元素值是否相等,==使用于对象比对时,是用来比对两个对象名称是否引用自同一个对象。范例5-10是这个概念的实例示范。

程序清单5-10:TestArrayValue.java

public class TestArrayValue {

public static void main(String[] args) {

int[] arr1 = {1, 2, 3, 4, 5};

int[] arr2 = {1, 2, 3, 4, 5};

int[] tmp = arr1;

System.out.println(arr1 == arr2);

System.out.println(arr1 == tmp);

System.out.println(arr2 == tmp);

}

}

在范例5-10中,虽然arr1与arr2中的元素值是相同的,arr1 == arr2并非比较arr1和arr2数组元素值,而是引用的比较,比较arr1和arr2是否指向的是内存中同一个位置。但实际上arr1与arr2是引用自不同的两个数组对象, arr1== arr2布尔表达式的值为false。将arr1指定给tmp来引用,由于tmp 与arr1是引用同一数组对象,所以进行==比较时会显示true;而tmp与arr2是引用自不同数组对象,所以进行==比较时会显示false。执行结果如下:

图5.10 TestArrayValue.java执行结果

进行数组复制的另一种方法是使用System类提供的arraycopy()方法。其语法如下:System.arraycopy(来源, 起始索引, 目的, 起始索引, 复制长度);

修改范例5-9,使用

System.arraycopy(array1, 0, array3, 0, array1.length);

替换掉原有的相应代码,实现数组的复制。测试程序,保证程序的运行结果与原来一致。

实验5.4.16: (D)for-each循环与数组

Java SE 5.0新增了for-each的语法,又称强化的for循环(Enhanced for Loop),应用于数组的依次存取。for-each循环的语法如下:

for (ElementType element : arrayName) {}

解释一下,冒号前面是声明一个临时变量,将在该foreach的代码段中进行引用;冒号后面是表达式,应该为集合或者数组。注意,临时变量element的类型ElementType必须与数组(或集合)元素的数据类型相同。

运行AccessArrayWithForEach.java(范例5-11),学习for-each循环的用法。

程序清单5-11:AccessArrayWithForEach.java

public class AccessArrayWithForEach {

public static void main(String[] args) {

String months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",

"July", "Aug", "Sep", "Oct", "Nov", "Dec"};

// Shortcut syntax loops through array months and assigns the next

// element to variable month for each pass through the loop

for(String month: months) {

System.out.println("month: " + month);

}

}

}

AccessArrayWithForEach.java中,每一次从数组months中取出的元素,会自动设定给month,不再需要判断是否超出了数组的长度。与AccessArrayWithForLoop.java(范例5-2)相比较,For-each的形式实现数组中的元素的依次存取,比for循环的代码简洁不少。但是这种形式的一个最大的缺点就是for-each没法定位访问单个元素,也就没办法修改,删除集合中的内容;同时,for-each也不能并行操作多个集合。所以,在编写代码时,还得看情况使用它。

二维数组如何使用for-each的方式来存取呢?要是了解数组本身就是一个对象,自然就会知道如何存取。举个例子:

int[][] arr = {{1, 2, 3},

{4, 5, 6},

{7, 8, 9}};

For-each形式的数组存取代码如下:

for ( int[] row : arr ) {

for ( int element : row ) {

System.out.println(element);

}

java web 工作原理总结

总结 第一章java web 工作原理 1.1、web应用程序有web服务器,web客服端浏览器,HTTP协议以及静态HTML文件。 Web服务器的作用是接受客服端请求,然后向客服端返回些结果;浏览器的作用是允许用户请求服务器上的某个资源,并且向用户显示请求的结果; HTML是用于告诉浏览器怎么样向用户显示内容; HTTP是web上客服端和服务器之间通信所用的协议。 1.1.2 HTTP协议将来自于客服端的请求信息封装成HTTP请求; 封装的信息当中包括请求行、请求头、消息体、分隔请求头、消息体的一个空行。 请求行是一个ASCII文本行,由三个标记组成:请求的HTTP方法、请求的URL、HTTP版本;中间用空格分开例如: GET /lovobook/index.html HTTP/1.0 在HTTP1.1版本中请求方法有八种分别是下面: GET:用于向服务器检索资源在HTTP请求头 POST:用于向服务器发送资源,并要求指定的URI处理在消息体HEAD:于GET方法相同,服务器只返回状态行和头标,并不返回请求文档。 PUT:请求服务器保持请求数据作为指定的URI新内容;

DELETE:请求服务器删除URI中命名的资源; OPTIONS:请求关于服务器支持的请求方法信息; TRACE:请求web服务器反馈HTTP请求和其头标;CONNECT:已文档化但当前未实现的一个方法,预留做隧道处理;请求头: HTTP协议使用HTTP头来传递请求的元信息。HTTP头是一个用冒号分隔的名称/值对,冒号前面是HTTP头的名称,后面是HTTP头的值。 1.1.3 HTTP响应包括:状态行、响应头、消息体、分割消息头、响应头。状态行里面出现: 1XX:表示信息,请求收到,继续处理。 2XX:表示成功 3XX:表示重定向 4XX:表示客服端错误 5XX:表示服务器错误 1.2 Web服务器的缺陷是只能向用户提供静态网页内容。 1.3 服务器端网页编程就是web服务器创建动态服务器端内容的过程。 1.3.1 服务器端网页编程出现得最早的技术就是CGI,它的缺点就是每次请求一个CGI资源,将在服务器上创建一个新的进程,并且通过标准输

JavaWeb程序设计教程课后练习答案

第1章 Web应用开发简介 习题答案 1.Web在组成上包括______和______两部分。 答案: 服务器 客户端 2.谈谈对面向对象的认识。 答案: 面向对象将将要解决的问题分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙解决问题中的各个步骤中的行为。面向对象编程方式是建立在面向过程编程方式基础上,其最重要的改变在于面向对象编程中,程序将围绕被操作的对象来设计,而不是操作本身。面向对象编程方式以类作为构造程序的基本单位,具有封装、抽象、继承、多态性等特点。 3.介绍几种常用的框架技术。 答案: Java中常用的框架。 1.Struts Struts是Apache 基金会Jakarta 项目组的一个开源项目,是一个基于Sun J2EE平台的MVC框架,它将Servlet和JSP标签作为实现自身功能的一部分。 2.WebWork WebWork是由OpenSymphony组织开发的,是一个基于Web的MVC框架。它在运行时通过Interceptor(拦截器)自动应用,因此脱离了Action类。 3.Struts 2 Struts 2是Apache基金会的一个开源项目,它建立在Struts框架与WebWork框架基础之上,继承了二者的优点,是目前非常流行的一个Web框架。 4.Spring Spring是一个以IoC和AOP为核心的轻量级容器框架。它提供了一系列的Java EE开发解决方案,包括表示层的Spring MVC、持久层的Spring JDBC以及业务层事务管理等众

多的企业级应用技术。 5.Hibernate Hibernate是一个ORM(对象关系映射)框架,它对JDBC进行了轻量级的封装。通过使用Hibernate框架,开发人员能够以面向对象的思维方式来操作数据库。 6.Ibatis 相对于Hibernate而言,Ibatis是一个“半自动化”的ORM实现框架,它主要致力于POJO与SQL之间的映射关系,是对“全自动化”ORM框架的一种有益补充。 7.EasyJWeb EasyJWeb是一个核心基于模板技术实现的MVC框架,主要致力于Java Web应用程序的快速开发。 4.IDE的用途是什么? 答案: IDE是一种用于辅助开发人员开发应用程序的应用软件,它一般包括代码编辑器、编译器、调试器和图形用户界面工具,有的还包括版本控制系统、性能分析器等更多工具,因此IDE也就具有了编写、编译、调试等多种功能。正是基于这些功能,使用IDE能够减少项目的开发周期,减轻程序员的工作量,提高应用程序的开发效率等。 5.Web应用服务器的用途是什么? Web应用服务器是为创建、部署、运行以及管理Web应用提供多种运行时服务(如事务、安全等等)的分布式系统,它是应用程序运行的一个基本环境。

java反射机制

Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在。灵活掌握Java反射机制,对大家以后学习框架技术有很大的帮助。 那么什么是Java的反射呢? 大家都知道,要让Java程序能够运行,那么就得让Java类要被Java虚拟机加载。Java类如果不被Java虚拟机加载,是不能正常运行的。现在我们运行的所有的程序都是在编译期的时候就已经知道了你所需要的那个类的已经被加载了。 Java的反射机制是在编译并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用在编译期并不知道的类。这样的特点就是反射。 那么Java反射有什么作用呢? 假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。 Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。大家都用过Jcreator和eclipse。当我们构建出一个对象的时候,去调用该对象的方法和属性的时候。一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。 Class类 要正确使用Java反射机制就得使用https://www.wendangku.net/doc/4a9145939.html,ng.Class这个类。它是Java反射机制的起源。当一个类被加载以后,Java虚拟机就会自动产生一个Class对象。通过这个Class对象我们就能获得加载到虚拟机当中这个Class对象对应的方法、成员以及构造方法的声明和定义等信息。 反射API ◆反射API用于反应在当前Java虚拟机中的类、接口或者对象信息 ◆功能 —获取一个对象的类信息. —获取一个类的访问修饰符、成员、方法、构造方法以及超类的信息. —检获属于一个接口的常量和方法声明. —创建一个直到程序运行期间才知道名字的类的实例. —获取并设置一个对象的成员,甚至这个成员的名字是 在程序运行期间才知道. —检测一个在运行期间才知道名字的对象的方法 利用Java反射机制我们可以很灵活的对已经加载到Java虚拟机当中的类信

JAVA反射机制(内含大量实例)

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。其中LEAD/LEAD++ 、OpenC++ 、MetaXa和OpenJava等就是基于反射机制的语言。最近,反射机制也被应用到了视窗系统、操作系统和文件系统中。 反射本身并不是一个新概念,它可能会使我们联想到光学中的反射概念,尽管计算机科学赋予了反射概念新的含义,但是,从现象上来说,它们确实有某些相通之处,这些有助于我们的理解。在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。可以看出,同一般的反射概念相比,计算机科学领域的反射不单单指反射本身,还包括对反射结果所采取的措施。所有采用反射机制的系统(即反射系统)都希望使系统的实现更开放。可以说,实现了反射机制的系统都具有开放性,但具有开放性的系统并不一定采用了反射机制,开放性是反射系统的必要条件。一般来说,反射系统除了满足开放性条件外还必须满足原因连接(Causally-connected)。所谓原因连接是指对反射系统自描述的改变能够立即反映到系统底层的实

际状态和行为上的情况,反之亦然。开放性和原因连接是反射系统的两大基本要素。 Java中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代表链接。反射允许我们在编写与执行时,使我们的程序代码能够接入装载到JVM中的类的内部信息,而不是源代码中选定的类协作的代码。这使反射成为构建灵活的应用的主要工具。但需注意的是:如果使用不当,反射的成本很高。 二、Java中的类反射: Reflection 是 Java 程序开发语言的特征之一,它允许运行中的Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pascal、C 或者 C++ 中就没有办法在程序中获得函数定义相关的信息。 1.检测类: 1.1 reflection的工作机制 考虑下面这个简单的例子,让我们看看 reflection 是如何工作的。

2020年Java自学路线图--Javaweb学习

2020年Java自学路线图--Javaweb学习Javaweb的学习时是Java学习路线图的第三个阶段,在Java学习路线图前两个阶段学习后开始学习Javaweb。具备基本的JavaWeb开发能力,熟悉Linux服 务器及相关软件的使用,可完成中小型企业级项目的开发需求。这个阶段学完后就可以考虑工作了,是不是很快? 这个阶段需要你掌握JavaWeb开发基础知识,熟悉Java基本开发环境、熟悉项目管理工具使用及Linux服务器使用,达到了这些才能满足Java软件开发行业的基本开发需求。

1.数据库的概念 2.常见的数据库软件 3.MySQL数据库的安装卸载 4.MySQL数据库的登录退出 5.MySQL的目录结构 6.SQL语句的分类 7.数据库和数据表的操作 8.数据的添加(insert) 9.数据的删除(delete) 10.数据的修改(update) 11.数据的查询(select) 12.数据的复杂查询 13.约束的使用 14.多表关系(一对一、一对多、多对多) 15.三大范式详解 16.数据库的还原和备份 17.多表查询操作 18.事务介绍 19.事务的隔离 20.数据库的用户管理和权限管理 21.黑马程序员视频库网址:https://www.wendangku.net/doc/4a9145939.html,(海量热门编程视频、资料免费学习) 22.学习路线图、学习大纲、各阶段知识点、资料网盘免费领取+QQ 1679806262

1.JDBC入门 2.DriverManager类详解 3.Connection类详解 4.Statement类详解 5.JDBC完成增删改查操作 6.ResultSet类详解 7.JDBC工具类的编写 8.PreparedStatement类详解 9.使用JDBC完成事务管理 10.连接池的介绍 11.c3p0连接池的使用 12.druid连接池的使用 13.创建druid连接池工具类 14.JDBCTemplate的使用HTML5&CSS3 1.B/S架构 2.HTML基本使用 3.HTML常用标签 4.CSS选择器 5.常用样式

JavaWeb

二、填空题 1.在编写Servlet时,需要继承HttpServlet类,在Servlet中声明doGet()和doPost()需要HttpServletRequest 和HttpServletResponse类型的两个参数。 2.jsp主要内置对象有:response、exception、pageContext、 request、session、application 、out、config、page。 3.使用useBean动作标记的时候scope属性有4种选项,作用范围由小到大是page、_requset_、_session ,application__,其中session _是指当关闭浏览器的时候这个javabean失效,_application_ 是指当关闭服务器的时候这个javabean失效。 1、控制一个Servlet的生命周期的方法有init( ), service( )和_ destroy( )。其中init()_在Servlet加载时调用,_destroy()__在撤消应用或关闭web container时调用,客户端的每次请求此Servlet时都会调用service()方法。Servlet通常只有一个实例,被所有的访问者共享,因此要注意资源的同步。 2. 在Servlet中要输出内容,使用HttpServletResponse的方法_setContentType 方法设置文档内容类型,对于文本类型调用方法_getWriter获得一个PrintWrite的输出流,对于二进制类型调用_getOutputStream获得ServeltOutputStream的输出流。调用HttpServletRequest的方法_getParameter获取有名参数,调用getInputStream获得一个ServletInputStream 的输入流。在Servlet中也可以调用ServletContext 和HttpServletRequest 的方法_ getRequestDispatche_获得RequestDispatcher, 将请求的处理权交给一个新的资源。 3.在Java Web开发中,跟踪客户状态的手段可通过_session_和_cookie_; 增加一个新的cookie, 调用HttpServletResponse的_addCookie _方法;要在服务器端查询cookie, 调用HttpServletRequest的getCookies方法。Session的类型是HttpSession, 获得session的途径是调用HttpServletRequest的方法是_ getSession_。 三.笔试题 18简述servlet进行中文处理的方法。 19请写出获取初始化参数的方法。 20简述使用Cookie进行会话跟踪过程。(写出主要步骤)

反射(reflection)学习整理

反射学习整理 【摘要】 本文主要通过自己对反射机制的总结编写的文档,主要目的就是为了自己以后能可以参考温习也可以方便刚刚入门的同仁们学习指导,通过doc的编写相信可以在帮助别人的同时提高自己。 反射机制; Reflection API; 如何使用反射机制; 反射机制的应用举例; 第一节反射机制 什么是反射机制,说的通俗一些就是在java运行期间动态加载一些不确定的类对象,那么我们如何使用一个类的呢?当然大多数情况下我们是使用一个确定的类,然后通过在内存中的加载再使用之。 其实在一个project中会有很多类,虚拟机并不是在每一次运行时都将所有的类都进行加载然后解析的,是在我们使用的过程中才会被加载,这个大家可以看一下ClassLoader(在后期中我也会编写ClassLoader相关的文章总结) 反射机制提供的功能: 加载运行时才能确定的数据类型; 解析类的结构,获取其内部的信息; 能够操作的类型或者实例; 1. 访问属性; 2. 调用方法; 3. 创建新的对象; 以上的功能我会在接下来的文字中都进行阐述,然后每一个功能点都会通过代码的形式进行逐一的说明举例; 1.1动态加载类 Java虚拟机在运行是能加载的类型有如下几种: 类接口; 数组; 枚举; 注解(Annotation,可以参见我的另一篇文档,《java Annotation学习文档》); 基本数据类型; 在类加载的时候,JVM会自动加载上述类型对应的Class对象。 package com.wangwenjun.demo;

import java.util.ArrayList; public class ReflectionDemo1 { private final static String LIST_STRING="java.util.ArrayList"; //动态加载java.util.ArrayList的类路径 @SuppressWarnings("unchecked") public static void main(String[] args) { try { Class clazz=Class.forName(LIST_STRING); //通过反射获取运行时的Class ArrayList list=(ArrayList) clazz.newInstance(); //通过newInstance方法获取Object list.add("hello"); System.out.println(list.size()+":"+list.get(0)); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 执行结果为:1:hello 通过上面的代码我们可以总结出来使用Reflection大致需要如下的几步: 获取目标对象的Class对象; 调用Class对象内省方法获取目标对类成员信息; 访问目标类的成员属性; 1.2解析类的结构 通过第一步的操作,我们获取了目标对象的class之后就可以解析出来class对应的内部结构;别不多说直接上代码,来看看如何解析出来目标对象; 我们定义一个Teacher类 package com.wangwenjun.demo; public class Teacher { private String username; private int age;

技术-Java防反编译技术

Java防反编译技术 1简介 1.1 Java软件面临的挑战 目前,由于黑客的频繁活动,使得Java类文件面临着反编译的挑战。有一些工具能够对Java 源代码进行反工程,其结果甚至以比普通Java文件更可读的方式, 尽管普通的Java文件(由于代码风格不同)有注释。许可证和软件过期对于用户们来说将变得无用。因此,防止软件被反编译或使得反编译的结果变得无意义对于Java来说非常重要。 一个Java类文件不一定非要存储在一个真正的文件里;它可以存在存贮器缓冲区,或从一个网络流获得。尽管防火墙和网络协议如TCP/IP有安全策略,黑客仍能打破访问限制获取一些类。尽管这些类能被混淆,他们(黑客)能够一步一步地分析和猜出每个指令的目的。如果这些代码是关键技术部分,例如是大产品的许可证或时间期满部分,反编译和分析指令的努力似乎很值得。如果这些关键类被隐藏或被一个关键字加密,黑客的非法入侵就很困难了。而且,未认证的软件复制对智能产权是普遍的攻击。还没有一个较好的通用方案来解决这类问题。 目前关于JA V A程序的加密方式不外乎JA V A混淆处理(Obfuscator)和运用ClassLoader 方法进行加密处理这两种方式(其他的方式亦有,但大多是这两种的延伸和变异)。 1.2 混淆处理 关于JA V A程序的加密方式,一直以来都是以JA V A混淆处理(Obfuscator)为主。这方面的研究结果也颇多,既有混淆器(如现在大名鼎鼎的JODE,SUN开发的JADE),也有针对反编译器的"炸弹"(如针对反编译工具Mocha的"炸弹" Crema和HoseMocha)。混淆器,从其字面上,我们就可以知道它是通过混淆处理JA V A代码,具体的说,就是更换变量名,函数名,甚至类名等方法使其反编译出来的代码变得不可理解。它的目的是:让程序无法被自动反编译,就算被反编译成功,也不容易被程序员阅读理解 其实这只是做到了视觉上的处理,其业务逻辑却依然不变,加以耐心,仍是可以攻破的,如果用在用户身份验证等目的上,完全可以找到身份验证算法而加以突破限制。 1.3 采用ClassLoader加密 JA V A虚拟机通过一个称为ClassLoader的对象装来载类文件的字节码,而ClassLoader 是可以由JA V A程序自己来定制的。ClassLoader是如何装载类的呢?ClassLoader根据类名在jar包中找到该类的文件,读取文件,并把它转换成一个Class对象。该方法的原理就是,

JavaWeb入门(容易)

《(容易)》试卷 得分 一、单选题(每题2分,共计30分) 1.在设计基于多层体系结构的大型应用时,充当界面且系统要不断进行升级,下面选项中最适合的开发模式是() A、 B、 C、 D、 2.接口中用于获取请求客户端的地址的方法是() A、() B、() C、() D、() 3.下列关于请求消息的请求行的写法中,正确的是() A、1.1 B、 1.1 C、 1.1 D、 4.下面选项中,可以实现浏览器重定向的状态码是() A、100 B、200 C、304 D、303 5.通过配置来解决请求参数的乱码问题,可以在文件中的节点下添加的属性是() A、”” B、”” C、”” D、”” 6.下列选项中,关于保存数据的位置,说法正确的是() A、数据保存在客户端 B、数据保存在服务器端 C、数据保存在客户端与服务器端各一份 D、以上说法都不对 7.下面选项中,用于强制使对象无效的方法是() A、. (); B、. (); C、. (); D、. (); 总分题号一二三四五题分 得分

8.下列是指令中的一些属性,其中,用于指定线程是否安全的属性是() A、 B、 C、 D、 9.在接口中,()方法的返回值类型是() A、 B、 C、 D、 10.在接口中,()方法获取请求客户端的完整主机,当无法解析出客户机的完整主机名时,将返回的是()A、 B、“” C、客户端的地址 11.下面选项中,在配置文件中定义,包括的名称和的实现类的结点是() A、; B、; C、; D、; 12.面哪项用于唯一标识放在上的每个资源() A、B、 C、 D、 13.下面选项中,哪个头字段用于指定文档最后的更改时间()A、 B、 C、 D、 14.下面选项中,用于判断当前对象是否是新创建的方法是() A、. (); B、. () C、. (); D、. (); 15.一个可以被映射成虚拟路径的个数是() A、1 B、2 C、0 D、多 得分 二、多选题(每题3分,共计30分)

一个例子让你了解Java反射机制

一个例子让你了解Java反射机制 JAVA反射机制: 通俗地说,反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,类,类的成员,我们在运行的时候还可以动态地去操作他们. 理论的东东太多也没用,下面我们看看实践 Demo ~ Demo: 1.package cn.lee.demo; 2. 3.import https://www.wendangku.net/doc/4a9145939.html,ng.reflect.Constructor; 4.import https://www.wendangku.net/doc/4a9145939.html,ng.reflect.Field; 5.import https://www.wendangku.net/doc/4a9145939.html,ng.reflect.InvocationTargetException; 6.import https://www.wendangku.net/doc/4a9145939.html,ng.reflect.Method; 7.import https://www.wendangku.net/doc/4a9145939.html,ng.reflect.Modifier; 8.import https://www.wendangku.net/doc/4a9145939.html,ng.reflect.TypeVariable; 9. 10.public class Main { 11. /** 12. * 为了看清楚Java反射部分代码,所有异常我都最后抛出来给虚拟机处 理! 13. * @param args 14. * @throws ClassNotFoundException 15. * @throws InstantiationException 16. * @throws IllegalAccessException 17. * @throws InvocationTargetException 18. * @throws IllegalArgumentException 19. * @throws NoSuchFieldException 20. * @throws SecurityException 21. * @throws NoSuchMethodException 22. */

Java Web快速入门教程

本文由godwjh贡献 ppt文档可能在WAP端浏览体验不佳。建议您优先选择TXT,或下载源文件到本机查看。 WEB工程快速入门 (JAVA WEB快速入门) 内容结构 1. 2. 3. 4. 5. 6. 7. 8. 9. WEB原理 HTML知识 搭建服务器、 servlet 处理表单 JSP 保持会话 JAVAbeans 连接数据库 1 WEB 原理 输入网址 B/S结构 HTTP://WWW.SOHU.COM 请求 浏览器 响应 静态网页 Browser SERVER WEB 原理 输入网址 B/S结构 HTTP://WWW.SOHU.COM 请求 浏览器 响应 动态网页 静态内容 Browser SERVER 2 HTML 知识->文档结构 主要内容放在这里 头 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">  2 HTML->常用标签 文本标签 创建最大的标题  创建最小的标题  创建黑体字 创建斜体字 创建打字机风格的字体 设置字体大小,从1到7 设置字体的颜色,使用名字或十六进制值  链接 创建一个超链接 创建一个自动发送电子邮件的链接 ……  格式排版 创建一个新的段落  将段落按左、中、右对齐  插入一个回车换行符  从两边缩进文本  创建一个定义列表  放在每个定义术语词之前  放在每个定义之前  创建一个标有数字的列表  放在每个数字列表项之前,并加上一个数字  创建一个标有圆点的列表  放在每个圆点列表项之前,并加上一个圆点  一个用来排版大块HTML段落的标签,也用于格式化表  图形元素 添加一个图像 加入一条水平线  表格 创建一个表格  开始表格中的每一行  开始一行中的每一个格子 设置表格头:一个通常使用黑体居中 文字的格子

深入理解Java反射机制汇总

深入理解Java反射机制 本文较为详细的分析了Java反射机制。分享给大家供大家参考,具体如下: 一、预先需要掌握的知识(java虚拟机) java虚拟机的方法区: java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区。方法区的主要作用是存储被装载的类的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class 中的类型信息,将这些信息存储到方法区中。这些信息主要包括: 1、这个类型的全限定名 2、这个类型的直接超类的全限定名 3、这个类型是类类型还是接口类型 4、这个类型的访问修饰符 5、任何直接超接口的全限定名的有序列表 6、该类型的常量池 7、字段信息 8、方法信息 9、除了常量以外的所有类变量 10、一个到class类的引用 等等(读者可以参考《深入java虚拟机》这本书的叙述) Class类: Class类是一个非常重要的java基础类,每当装载一个新的类型的时候,java虚拟机都会在java堆中创建一个对应于新类型的Class实例,该实例就代表此类型,通过该Class实例我们就可以访问该类型的基本信息。上面说到在方法区中会存储某个被装载类的类型信息,我们就可以通过Class实例来访问这些信息。比如,对于上面说到的信息Class中都有对应的方法,如下:

1、getName();这个类型的全限定名 2、getSuperClass();这个类型的直接超类的全限定名 3、isInterface();这个类型是类类型还是接口类型 4、getTypeParamters();这个类型的访问修饰符 5、getInterfaces();任何直接超接口的全限定名的有序列表 6、getFields();字段信息 7、getMethods();方法信息 等等(读者可以自己参看jdk帮助文档,得到更多的信息) 二、java反射详解 反射的概念:所谓的反射就是java语言在运行时拥有一项自观的能力,反射使您的程序代码能够得到装载到JVM中的类的内部信息,允许您执行程序时才得到需要类的内部信息,而不是在编写代码的时候就必须要知道所需类的内部信息,这使反射成为构建灵活的应用的主要工具。 反射的常用类和函数:Java反射机制的实现要借助于4个类:Class,Constructor,Field,Method;其中class代表的是类对象,Constructor-类的构造器对象,Field-类的属性对象,Method -类的方法对象,通过这四个对象我们可以粗略的看到一个类的各个组成部分。其中最核心的就是Class类,它是实现反射的基础,它包含的方法我们在第一部分已经进行了基本的阐述。应用反射时我们最关心的一般是一个类的构造器、属性和方法,下面我们主要介绍Class 类中针对这三个元素的方法: 1、得到构造器的方法 Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数,Constructor[] getConstructors() -- 获得类的所有公共构造函数 Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关) Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关) 2、获得字段信息的方法

java反射机制详解与应用

java有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods1。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflection和introspection是常被并提的两个术语。 这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等等)、superclass(例如Object)、实现之interfaces (例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。 目前好多框架都会用到java的反射机制。比如struts2,sping,hibernate。 如果我们不用struts2,自己写一个类似的功能也是可以实现的,比如浏览器通过HTTP发送数据,而这些数据都是字符串,我们接受到这些字符串时,可以通过反射去构造一个对象(通过拦截器做成框架的功能),这样就可以用对象的get和set方法了,而不用原始的getPeremter 方法。事实上,在struts2出来之前,我们又不想用struts1的ActionForm就做过这样项目。 一、Class object 的产生方式有以下几种。 1、运用getClass() 注:每个class 都有此函数 String str = "abc"; Class c1 = str.getClass(); 2、运用static method Class.forName()(最常被使用) Class c1 = Class.forName ("https://www.wendangku.net/doc/4a9145939.html,ng.String"); Class c2 = Class.forName ("java.awt.Button"); 3、运用.class 语法 Class c1 = String.class; Class c2 = java.awt.Button.class; 4、运用primitive wrapper classes的TYPE 语法 Class c1 = Integer.TYPE; Class c2 = Long.TYPE; 二、Java类反射中的主要方法 对于以下三类组件中的任何一类来说-- 构造函数、字段和方法-- https://www.wendangku.net/doc/4a9145939.html,ng.Class 提供四种

javaweb实训总结

javaweb实训总结 javaweb实训总结 实训已经进行两周多了,还有一周就要正式结束了,突然发现自己似乎又重蹈覆辙了,再一次一次的不经意中和某些人的就距离却是越来越来大,总是想偷一下懒,总是想着马马虎虎过去算了,没有那么精打细算过。结果不经意有些人人开始脱颖而出,有些人开始展露锋芒,而我也开始黯淡下去。我是想好好学学别人的,结果画虎不成反类犬。原来我也是不轻易臣服的人,我即便不去领导他们也没有人可以领导我。给我分的实训小组连个能交流的人都没有,身边一个研究生只会不停地打击我,我只能不知所谓的笑笑。这个项目小组真让我郁闷,组长谁也领导不了,组长不是我,我也懒得管,乐得清闲。 这两周究竟自己学到了什么,确实在脑海中总还是模糊不清的,J2SE,J2EE,HTML,JScrip特效,CSS,JA V Aweb,Servlet,JDBC,数据库快速建模,数据池,单态模式,JFreechart,俄罗斯方块项目,人力资源项目,购物网项目,这都算是过来了,可是心里却不是很有谱自己心里七上八下的,自知学的只有四成火候,又不断地被人打击打击么还没有可以交流,心中这两天的抑郁让我难以忍受,总是喉咙里很堵,心里着实闷得难受。回去想跟室友聊聊,他只说了一句,寂寞才说爱,活该。我就更郁闷了,我一直对自己说我只是活着我只是深爱着。明天就要进行最后一周实训了,各项目都到了结束完善阶段,也是所学的整理复习阶段。看着周围有人夸夸其谈,有人韬光养晦,自己心里也很没底,项目结项之后还有个考核我

都十分担忧。其实这各阶段我更担忧的是我发现自己的学力已经下降,可能是长时间习惯不听老师讲课,只靠自学和考前突击。现在听讲师讲课总是听着听着就跑神了,听着听着就觉得没意思了,总想自己看书自己单干,可真的有时间的时候我却提不起精神去单搞,总是事倍功半花了三四个小时有时候只是把讲师四十分钟的搞完。然后精疲力竭的倒下。 拥有太多的东西总是不会去珍惜的。我懒惰的恶习让我异常痛苦。我现在唯一拥有的财富就剩下我的青春了,我发誓我会努力努力再努力,捍卫自己的青春,我说过我会成为伟人的。以后我会给自己出本自传的。人生只有一次,人生在世至少不能辜负自己。 总结二:javaweb实训总结 突击了三个多月的javaweb,有了许多心得体会,在这里小小的发些感慨,希望对刚刚入门的朋友有些帮助。毕竟我现在也算是一个过来人了。 起初我在大学的时候只是学过一些基本的JSP,记得那时候做东西的时候不懂得异常处理,更不懂得安全问题,因为没见过那么大的天空,就满足在自己头上的云彩。即将毕业走出了校园,见识到了真正的程序员,看到了他们的工作方式,颇有感悟。记得在上学的时候一直想学servlet,但是虽然自己买了许多的书,其中包括孙鑫的《JSPServlet 深入详解》,可是由于自己的惰性,始终没能动手演练,因为我们常用的Servlet是基于直至遇到了方老师,虽然不能说听君一席话,胜读十年书,但是对我来说真是受益匪浅,此时也算是我再一次的重新开始javaweb的学习。由于有过一个多月的经验,现在再来学习第二遍,也算总结了点方法。下面就浅谈一下自己的体会。

Java反射访问私有变量和私有方法

Java反射访问私有变量和私有方法 引言 对于软件开发人员来说,单元测试是一项必不可少的工作。它既可以验证程序的有效性,又可以在程序出现BUG 的时候,帮助开发人员快速的定位问题所在。但是,在写单元测试的过程中,开发人员经常要访问类的一些非公有的成员变量或方法,这给测试工作带来了很大的困扰。本文总结了访问类的非公有成员变量或方法的四种途径,以方便测试人员在需要访问类非公有成员变量或方法时进行选择。 尽管有很多经验丰富的程序员认为不应该提倡访问类的私有成员变量或方法,因为这样做违反了Java 语言封装性的基本规则。然而,在实际测试中被测试的对象千奇百怪,为了有效快速的进行单元测试,有时我们不得不违反一些这样或那样的规则。本文只讨论如何访问类的非公有成员变量或方法,至于是否应该在开发测试中这样做,则留给读者自己根据实际情况去判断和选择。 方法一:修改访问权限修饰符 先介绍最简单也是最直接的方法,就是利用Java 语言自身的特性,达到访问非公有成员的目的。说白了就是直接将private 和protected 关键字改为public 或者直接删除。我们建议直接删除,因为在Java 语言定义中,缺省访问修饰符是包可见的。这样做之后,我们可以另建一个源码目录——test 目录(多数IDE 支持这么做,如Eclipse 和JBuilder),然后将测试类放到test 目录相同包下,从而达到访问待测类的成员变量和方法的目的。此时,在其它包的代码依然不能访问这些变量或方法,在一定程度上保障了程序的封装性。 下面的代码示例展示了这一方法。 清单1. 原始待测类 A 代码 public class A { private String name = null; private void calculate() { } }

java反射原理

Java反射机制 一、什么是反射机制 简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。 二、哪里用到反射机制 有些时候,我们用过一些知识,但是并不知道它的专业术语是什么,在刚刚学jdbc时用过一行代码, Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那时候只知道那行代码是生成驱动对象实例,并不知道它的具体含义。听了反射机制这节课后,才知道,原来这就是反射,现在很多开框架都用到反射机制,hibernate、struts都是用反射机制实现的。 三、反射机制的优点与缺点 为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念,静态编译:在编译时确定类型,绑定对象,即通过。 动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多 态的应用,有以降低类之间的藕合性。 一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中 它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。

它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。 四、利用反射机制能获得什么信息 一句话,类中有什么信息,它就可以获得什么信息,不过前提是得知道类的名字,要不就没有后文了首先得根据传入的类的全名来创建Class对象。 Class c=Class.forName("className");注明:className必须为全名,也就是得包含包名,比如, https://www.wendangku.net/doc/4a9145939.html,erInfo; Object obj=c.newInstance();//创建对象的实例 OK,有了对象就什么都好办了,想要什么信息就有什么信息了。 获得构造函数的方法 Constructor getConstructor(Class[] params)//根据指定参数获得public构造器 Constructor[] getConstructors()//获得public的所有构造器 Constructor getDeclaredConstructor(Class[] params)//根据指定参数获得public和非public的构造器 Constructor[] getDeclaredConstructors()//获得public的所有构造器 获得类方法的方法 Method getMethod(String name, Class[] params),根据方法名,参数类型获得方法 Method[] getMethods()//获得所有的public方法 Method getDeclaredMethod(String name, Class[] params)//根据方法名和参数类型,获得public和非public 的方法

java反射机制详解 及 Method.invoke解释

java反射机制详解及Method.invoke解释 JAVA反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够 知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 Java反射机制主要提供了以下功能:在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。 1. 得到某个对象的属性 Java代码public Object getProperty(Object owner, String fieldName) throws Exception { Class ownerClass = owner.getClass(); Field field = ownerClass.getField(fieldName); Object property = field.get(owner); return property; } Class ownerClass = owner.getClass():得到该对象的Class。Field field = ownerClass.getField(fieldName):通过Class 得到类声明的属性。Object property = field.get(owner):通过对象得到该属性的实例,如果这个属性是非公有的,这里

会报IllegalAccessException。2. 得到某个类的静态属性Java代码public Object getStaticProperty(String className, String fieldName) throws Exception { Class ownerClass = Class.forName(className); Field field = ownerClass.getField(fieldName); Object property = field.get(ownerClass); return property; } Class ownerClass = Class.forName(className) :首先得到这个类的Class。Field field = ownerClass.getField(fieldName):和上面一样,通过Class 得到类声明的属性。Object property = field.get(ownerClass) :这里和上面有些不同,因为该属性是静态的,所以直接从类的Class里取。3. 执行某对象的方法 Java代码public Object invokeMethod(Object owner, String methodName, Object[] args) throws Exception { Class ownerClass = owner.getClass(); Class[] argsClass = new Class[args.length]; for (int i = 0, j = args.length; i < j; i++) { argsClass[i] = args[i].getClass(); } Method method =

相关文档 最新文档