第1关:Object类
任务描述
本关任务:掌握Object类及Object类的一些常用方法。
相关知识
为了完成本关任务,你需要掌握:
1.什么是Object类;
2.Object类的方法;
3.Java对象克隆。
什么是Object类
Java中有一个比较特殊的类,就是 Object 类,它是所有类的父类,如果一个类没有使用extends关键字明确标识继承另外一个类,那么这个类就默认继承 Object 类。因此,Object 类是 Java 类层中的最高层类,是所有类的超类。换句话说,Java 中任何一个类都是它的子类。由于所有的类都是由 Object 类衍生出来的,所以 Object 类中的方法适用于所有类。
public class Person //当没有指定父类时,会默认 Object 类为其父类{...}
上面的程序等价于:
public class Person extends Object{...}
如果想引用你不知道的类型的对象,使用Object类是没有错的。请注意,父类引用变量可以引用子类对象,称为向上转换。下面举一个例子,有一个getObject()方法返回一个对象,但它可以是任何类型,如:Employee,Student等这样的类,我们可以使用Object类引用来引用该对象。 例如:
Object obj=getObject();//we don't know what object will be returned from this method
Object类为所有对象提供了一些常见的行为,如对象可以进行比较,对象可以克隆,对象可以通知等。

Object类的方法
Object类提供了许多方法。 它们如下:

Object类的常用方法有: toString()和equals()方法。
1.关于toString()方法
-
在
Object类里面定义toString()方法的时候返回的对象的哈希code码(对象地址字符串); -
可以通过重写
toString()方法表示出对象的属性。
此方法是在打印对象时被调用的,下面有两个范例,一个是没复写toString()方法,另一个是复写了 toString()方法,读者可比较两者的区别。
-
package educoder; -
public class TestToStringDemo1 { -
public static void main(String[] args) { -
Person p = new Person(); -
System.out.println(p); -
} -
} -
class Person extends Object { -
String name = "张三"; -
int age = 18; -
}
输出结果: educoder.Person@7852e922
从上面的程序中可以发现,在打印对象p的时候实际上打印出的是一些无序的字符串,这样的字符串很少有人能看懂什么意思,之后可以再观察下面的范例,下面的范例复写了Object类中的 toString()方法。
-
package educoder; -
public class TestToStringDemo2 { -
public static void main(String[] args) { -
Person p = new Person(); -
System.out.println(p); -
} -
} -
class Person extends Object { -
String name = "张三"; -
int age = 18; -
// 复写Object类中的toString()方法 -
public String toString() { -
return "我是:" + this.name + ",今年:" + this.age + "岁"; -
} -
}
输出结果: 我是:张三,今年:18岁
与 TestToStringDemo1.java 程序相比,程序TestToStringDemo2.java 在 Person 类中明确复写了 toString()方法,这样在打印对象p的时候,实际上是去调用了 toString()方法,只是并没有明显的指明调用 toString()方法而已,此时第 6 行相当于:
System.out.println(p.toString());
2.关于equals()方法
比较的是对象的引用是否指向同一块内存地址,一般情况下,比较两个对象时是比较它的值是否一致,那如何解决呢?思路也比较简单,重写equals()方法。
在不重写的情况下,我们先看下程序执行情况,创建两个相同类型的对象,并判断对象是否相等。
-
package educoder; -
public class test { -
public static void main(String[] args) { -
Dog dog = new Dog(); -
dog.name = "jack"; -
Dog dog1 = new Dog(); -
dog1.name = "jack"; -
System.out.println(dog); -
System.out.println(dog1); -
if (dog.equals(dog1)) { -
System.out.println("两个对象是相同的"); -
} else { -
System.out.println("两个对象是不相同的"); -
} -
} -
} -
class Animal { -
} -
class Dog extends Animal { -
int age = 20; -
String name = "rose"; -
public String toString() { -
return "Dog [age=" + age + ", name=" + name + "]"; -
} -
}
输出结果: Dog [age=20, name=jack] Dog [age=20, name=jack] 两个对象是不相同的
分析下 : 两个对象分别new了一次,开辟了两个不同内存空间,内存地址不同。object提供的equals()是用来比较的是对象的引用是否指向同一块内存地址。很显然,内存地址不一样,所以是不相等的,跟属性值是否一样完全没有任何关系。
一般情况下,我们是需要判断对象的属性值相等的,那么如何重写 equals()方法呢?通过Eclipse(集成开发环境)提供的快捷键,Dog类中出现如下方法,方法的解释也放在代码中一并进行解释如下:
-
package educoder; -
public class test { -
public static void main(String[] args) { -
Dog dog = new Dog(); -
dog.name = "jack"; -
Dog dog1 = new Dog(); -
dog1.name = "jack"; -
System.out.println(dog); -
System.out.println(dog1); -
if (dog.equals(dog1)) { -
System.out.println("两个对象是相同的"); -
} else { -
System.out.println("两个对象是不相同的"); -
} -
} -
} -
class Animal { -
} -
class Dog extends Animal { -
int age = 20; -
String name = "rose"; -
public String toString() { -
return "Dog [age=" + age + ", name=" + name + "]"; -
} -
/* getClass() 得到的是一个类对象 */ -
@Override -
public boolean equals(Object obj) { -
if (this == obj)// 两个对象的引用是否相同,如果相同,说明两个对象就是同一个 -
return true; -
if (obj == null)// 如果比较对象为空,不需要比较,肯定不相等 -
return false; -
if (getClass() != obj.getClass())// 比较两个对象的类型是否相同,如果不同,肯定不相同 -
return false; -
Dog other = (Dog) obj;// 转化成相同类型后,判断属性值是否相同 -
if (name == null) { -
if (other.name != null) -
return false; -
} else if (!name.equals(other.name)) -
return false; -
return true; -
} -
}
输出结果: Dog [age=20, name=jack] Dog [age=20, name=jack] 两个对象是相同的
equals() 和 == 的区别:
- 在Java中,任何类型的数据都可以用 “==”进行比较是不是相等,一般用于基本数据类型的比较,比较器存储的值是否相等。但是如果用于引用类型的比较,则是比较所指向对象的地址是否相等,在这点上,跟
object类提供的equals()方法的作用是一致的。 - 对于
equals()方法
-
首先,不能用于基本数据类型的变量之间的比较相等;
-
如果没有对
equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址; -
诸如
String、Date等类都对equals方法进行了重写,比较的是所指向的对象的内容。
Java对象克隆
对象克隆是一种创建对象的精确副本的方法。 Object类的clone()方法用于克隆对象。java.lang.Cloneable接口必须由我们要创建其对象克隆的类实现。如果我们不实现Cloneable接口,clone()方法将生成CloneNotSupportedException。
clone()方法在Object类中定义。 clone()方法的语法如下:
protected Object clone() throws CloneNotSupportedException
为什么要使用clone()方法?
clone()方法保存用于创建对象的精确副本的额外处理任务。 如果我们使用new关键字执行它,它将需要执行大量的处理,这就是为什么我们使用对象克隆。 对象克隆的优点:
- 少处理任务。
clone()方法示例(对象克隆)
-
package educoder; -
public class Student implements Cloneable { -
int rollno; -
String name; -
Student(int rollno, String name) { -
this.rollno = rollno; -
this.name = name; -
} -
public Object clone() throws CloneNotSupportedException { -
return super.clone(); -
} -
public static void main(String args[]) { -
try { -
Student s1 = new Student(101, "amit"); -
Student s2 = (Student) s1.clone(); -
System.out.println(s1.rollno + " " + s1.name); -
System.out.println(s2.rollno + " " + s2.name); -
} catch (CloneNotSupportedException c) { -
} -
} -
}
输出结果: 101 amit 101 amit
从上面的例子可以看出,两个引用变量都有相同的值。 因此,clone()将对象的值复制到另一个对象。 因此,在实际应用中我们不需要编写显式代码将对象的值复制到另一个对象。如果通过new关键字创建另一个对象并将另一个对象的值赋给这个对象,则需要对该对象进行大量处理。 所以为了节省额外的处理任务,我们使用clone()方法。
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
-
Demo类和Person类已经写好,在测试类中创建Demo类对象d1,传入输入值num1,d1调用toString方法并打印输出该值; -
创建
Demo类对象d2,同样传入输入值num1,打印判断d1和d2是否相等(实际是比较地址); -
创建
Person类对象p,传入输入值num2,打印判断d1和p是否相等(实际是比较地址);
测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。
测试输入: 100 100
预期输出: Demo:100 true false
开始你的任务吧,祝你成功!
package case1;
import java.util.Scanner;
public class ObjectTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int num1 = sc.nextInt();
int num2 = sc.nextInt();
// 在测试类中创建Demo类对象d1,传入输入值num1, d1调用toString方法并打印输出该值
// 创建Demo类对象d2,同样传入输入值num1,打印判断d1和d2是否相等(实际是比较地址)
/********* Begin *********/
Demo d1=new Demo(num1);
System.out.println(d1.toString());
Demo d2=new Demo(num1);
if(d1.equals(d2)){
System.out.println("true");
}else{
System.out.println("false");
}
/********* End *********/
// 创建Person类对象p,传入输入值num2,打印判断d1和p是否相等(实际是比较地址)
/********* Begin *********/
Person p=new Person(num2);
if(d1.equals(p)){
System.out.println("true");
}else{
System.out.println("false");
}
/********* End *********/
}
}
第2关:JAVA基础类型包装类-练习
任务描述
通过所学知识,完成本关任务。
相关知识
略
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
编写测试类,输入int型值aa传递给Integer类对象a,String型值bb传递给Integer类对象b,输入int型值c,aa、bb、c对应的数值相等;
输入String型值str11传递给String类对象str1,输入String型值str22传递给String类对象str2,str1和str2对应的内容相同;
打印输出a == b、a == c、b == c、a.equals(b);
打印输出str1 == str2、str1.equals(str2)。
测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。
测试输入:
100
100
100
educoder
educoder
预期输出:
false
true
true
true
false
true
开始你的任务吧,祝你成功!
package case2;
import java.util.Scanner;
public class WrapperTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int aa = sc.nextInt();
String bb = sc.next();
int c = sc.nextInt();
String str11 = sc.next();
String str22 = sc.next();
// 包装类中“==”与equals的用法比较
// 值得注意的是,包装类中的equals方法和String类一样,都是重写了Object类中的equals方法,因此比较的是内容而不是地址,
// 而“==”比较的依然是引用变量的地址,只是当包装类型和与之相对应的基本类型进行“==”比较时会先做自动拆箱处理。
/********* Begin *********/
Integer a=new Integer(aa);
Integer b=Integer.parseInt(bb);
String str1=new String(str11);
String str2=new String(str22);
System.out.println(a==b);
System.out.println(a==c);
System.out.println(b==c);
System.out.println(a.equals(b));
System.out.println(str1==str2);
System.out.println(str1.equals(str2));
/********* End *********/
}
}
第3关:String&StringBuilder&StringBuffer类-练习
任务描述
通过所学知识,完成本关任务。
相关知识
略
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
编写测试类,输入一个标准的网址,输出其域名的主体;
将该主体转换为大写,打印输出;
具体输出要求请看测试说明。
测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。
测试输入:
https://www.educoder.net/
预期输出:
educoder
EDUCODER
开始你的任务吧,祝你成功!
package case3;
import java.util.Scanner;
public class StringTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str = sc.next();
// String substring(int start,int end)
// 截取字符串,传入的两个参数分别为要截取边界的下标
// 在java api 中,通常使用两个数字表示范围时,都是含头不含尾,即包含起始下标对应的内容,但不包含结束下标的处对应的内容
// String toUpperCase() 将当前字符串中的英文部分转换为全大写
/********* Begin *********/
String str1=str.substring(12,str.lastIndexOf('.'));
if(str1.indexOf('.')>0){
str1=str1.substring(0,str1.indexOf('.'));
}
System.out.println(str1);
str1=str1.toUpperCase();
System.out.println(str1);
/********* End *********/
}
}
第4关:Random类
任务描述
本关任务:掌握Random类以及Random类的使用。
相关知识
为了完成本关任务,你需要掌握:
1.Random类;
2.Random对象的生成;
3.Random类中的常用方法。
Random类
Random类位于java.util包下,Random类中实现的随机算法是伪随机,也就是有规则的随机。在进行随机时,随机算法的起源数字称为种子数(seed),在种子数的基础上进行一定的变换,从而产生需要的随机数字。
相同种子数的Random对象,相同次数生成的随机数字是完全相同的。也就是说,两个种子数相同的Random对象,第一次生成的随机数字完全相同,第二次生成的随机数字也完全相同。这点在生成多个随机数字时需要特别注意。
Random对象的生成
Random类包含两个构造方法,下面依次进行介绍:
public Random()
该构造方法使用一个和当前系统时间对应的相对时间有关的数字作为种子数,然后使用这个种子数构造Random对象。
public Random(long seed)
该构造方法可以通过制定一个种子数进行创建。
示例代码:
Random r = new Random();Random r1 = new Random(10);
再次强调:种子数只是随机算法的起源数字,和生成的随机数字的区间无关。
验证:相同种子数的Random对象,相同次数生成的随机数字是完全相同的。
-
package educoder; -
import java.util.Random; -
public class RandomTest { -
public void random() { -
int i = 0; -
int j = 0; -
Random random = new Random(1); -
Random random1 = new Random(1); -
i = random.nextInt(); -
j = random1.nextInt(); -
System.out.println("i:" + i + "\nj:" + j); -
} -
public static void main(String[] args) { -
RandomTest tt = new RandomTest(); -
tt.random(); -
} -
}
输出结果: 第一次: i:-1155869325 j:-1155869325
修改一下起源数字,让其等于100。
Random random = new Random(100);Random random1 = new Random(100);
输出结果: i:-1193959466 j:-1193959466
Random类中的常用方法
Random类中的方法比较简单,每个方法的功能也很容易理解。需要说明的是,Random类中各方法生成的随机数字都是均匀分布的,也就是说区间内部的数字生成的几率是均等的。下面对这些方法做一下基本的介绍:
-
package educoder; -
import java.util.Random; -
public class RandomTest { -
public static void main(String[] args) { -
Random random = new Random(); -
System.out.println("nextInt():" + random.nextInt()); // 随机生成一个整数,这个整数的范围就是int类型的范围-2^31~2^31-1 -
System.out.println("nextLong():" + random.nextLong()); // 随机生成long类型范围的整数 -
System.out.println("nextFloat():" + random.nextFloat()); // 随机生成[0, 1.0)区间的小数 -
System.out.println("nextDouble():" + random.nextDouble()); // 随机生成[0, 1.0)区间的小数 -
System.out.println("nextBoolean():"+random.nextBoolean());//随机生成一个boolean值,生成true和false的值几率相等,也就是都是50%的几率 -
System.out.println("nextGaussian():"+random.nextGaussian());//随机生成呈高斯(“正态”)分布的 double 值,其平均值是 0.0,标准差是 1.0 -
byte[] byteArr = new byte[5]; -
random.nextBytes(byteArr); // 随机生成byte,并存放在定义的数组中,生成的个数等于定义的数组的个数 -
System.out.print("nextBytes():"); -
for (int i = 0; i < byteArr.length; i++) { -
System.out.print(byteArr[i]+"\t"); -
} -
System.out.println(); -
/** -
* random.nextInt(n) -
* 随机生成一个正整数,整数范围[0,n),包含0而不包含n -
* 如果想生成其他范围的数据,可以在此基础上进行加减 -
* -
* 例如: -
* 1. 想生成范围在[0,n]的整数 -
* random.nextInt(n+1) -
* 2. 想生成范围在[m,n]的整数, n > m -
* random.nextInt(n-m+1) + m -
* random.nextInt() % (n-m) + m -
* 3. 想生成范围在(m,n)的整数 -
* random.nextInt(n-m+1) + m -1 -
* random.nextInt() % (n-m) + m - 1 -
* ......主要是依靠简单的加减法 -
*/ -
System.out.println("nextInt(10):" + random.nextInt(10)); // 随机生成一个整数,整数范围[0,10) -
for (int i = 0; i < 5; i++) { -
System.out.println("我生成了一个[3,15)区间的数,它是:" + (random.nextInt(12) + 3)); -
} -
/** -
* random.nextDouble() -
* 例如: -
* 1.生成[0,1.0)区间的小数 -
* double d1 = random.nextDouble();//直接使用nextDouble方法获得。 -
* 2.生成[0,5.0)区间的小数 -
* double d2 = random.nextDouble() * 5;//因为扩大5倍即是要求的区间。同理,生成[0,d)区间的随机小数,d为任意正的小数,则只需要将nextDouble方法的返回值乘以d即可。 -
* 3.生成[1,2.5)区间的小数 -
* double d3 = r.nextDouble() * 1.5 + 1;//生成[1,2.5)区间的随机小数,则只需要首先生成[0,1.5)区间的随机数字,然后将生成的随机数区间加1即可。 -
* ......同理,生成任意非从0开始的小数区间[d1,d2)范围的随机数字(其中d1不等于0),则只需要首先生成[0,d2-d1)区间的随机数字,然后将生成的随机数字区间加上d1即可。 -
* -
*/ -
} -
}
输出结果: nextInt():1842341002 nextLong():4006643082448092921 nextFloat():0.88948154 nextDouble():0.5635189241159165 nextBoolean():false nextGaussian():1.3191426544832998 nextBytes():36 100 94 14 -98 nextInt(10):1 我生成了一个[3,15)区间的数,它是:5 我生成了一个[3,15)区间的数,它是:10 我生成了一个[3,15)区间的数,它是:10 我生成了一个[3,15)区间的数,它是:11 我生成了一个[3,15)区间的数,它是:6
JDK1.8新增方法:
-
package educoder; -
import java.util.Random; -
public class RandomTest2 { -
/** -
* 测试Random类中 JDK1.8提供的新方法 JDK1.8新增了Stream的概念 在Random中,为double, int, -
* long类型分别增加了对应的生成随机数的方法 鉴于每种数据类型方法原理是一样的,所以,这里以int类型举例说明用法 -
*/ -
public static void main(String[] args) { -
Random random = new Random(); -
random.ints(); // 生成无限个int类型范围内的数据,因为是无限个,这里就不打印了,会卡死的...... -
random.ints(10, 100); // 生成无限个[10,100)范围内的数据 -
/** -
* 这里的toArray 是Stream里提供的方法 -
*/ -
int[] arr = random.ints(5).toArray(); // 生成5个int范围类的整数。 -
System.out.println(arr.length); -
for (int i = 0; i < arr.length; i++) { -
System.out.println(arr[i]); -
} -
// 生成5个在[10,100)范围内的整数 -
arr = random.ints(5, 10, 100).toArray(); -
for (int i = 0; i < arr.length; i++) { -
System.out.println(arr[i]); -
} -
/** -
* 对于 random.ints(); random.ints(ori, des); -
* 两个生成无限个随机数的方法,我们可以利用Stream里的terminal操作,来截断无限这个操作 -
*/ -
// limit表示限制只要5个,等价于random.ints(5) -
arr = random.ints().limit(5).toArray(); -
System.out.println(arr.length); -
for (int i = 0; i < arr.length; i++) { -
System.out.println(arr[i]); -
} -
// 等价于random.ints(5, 10, 100) -
arr = random.ints(10, 100).limit(5).toArray(); -
for (int i = 0; i < arr.length; i++) { -
System.out.println(arr[i]); -
} -
} -
}
输出结果: 5 1801462452 -1812435985 -1073912930 1160255210 -1342018704 80 54 16 67 82 5 -1161610558 283052091 797550518 -275356995 -1661722790 11 27 27 52 54
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
-
设计一个密码的自动生成器:密码由大写字母/小写字母/数字组成,生成六位随机密码。
-
分别以
1、2、3作为种子数创建Random对象,生成六位随机密码进行测试。 -
具体输出要求请看测试说明。
测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。
测试输入: 1 预期输出: NAvZuG
开始你的任务吧,祝你成功!
package case4;
//密码的自动生成器:密码由大写字母/小写字母/数字组成,生成六位随机密码
import java.util.Random;
import java.util.Scanner;
public class RandomTest {
public static void main(String[] args) {
// 定义一个字符型数组
char[] pardStore = new char[62];
// 把所有的大写字母放进去 把所有的小写字母放进去 把0到9放进去
/********* Begin *********/
for(int i=0;i<26;i++)
{
pardStore[i]=(char)('A'+i);
pardStore[26+i]=(char)('a'+i);
}
for(int i=0;i<10;i++)
{
pardStore[52+i]= (char)('0' + i);
}
/********* End *********/
// 分别以1、2、3作为种子数 生成6位随机密码
Scanner sc = new Scanner(System.in);
int seed = sc.nextInt();
/********* Begin *********/
Random r=new Random(seed);
String str="";
int[] arr=r.ints(6,0,62).toArray();
for(int i=0;i<6;i++)
{
str+=pardStore[arr[i]];
}
System.out.print(str);
/********* End *********/
}
}
第5关:Date类和SimpleDateFormat类的用法
任务描述
本关任务:掌握Date类以及DateFormat类的相关用法。
相关知识
为了完成本关任务,你需要掌握:
1.Java日期时间;
2.使用 SimpleDateFormat 格式化日期。
Java日期时间
java.util包提供了Date类来封装当前的日期和时间。Date类提供两个构造函数来实例化Date对象。
第一个构造函数使用当前日期和时间来初始化对象。
Date( )
第二个构造函数接收一个参数,该参数是从1970年1月1日起的毫秒数。
Date(long millisec)
Date对象创建以后,可以调用下面的方法。


获取当前日期时间:
Java中获取当前日期和时间很简单,使用Date对象的toString()方法来打印当前日期和时间,如下所示:
-
package educoder; -
import java.util.Date; -
public class DateDemo { -
public static void main(String args[]) { -
// 初始化 Date 对象 -
Date date = new Date(); -
// 使用 toString() 函数显示日期时间 -
System.out.println(date.toString()); -
} -
}
输出结果: Sun Aug 12 23:33:44 CST 2018
日期比较:
Java使用以下三种方法来比较两个日期:
-
使用
getTime()方法获取两个日期自1970年1月1日经历的毫秒数值,然后比较这两个值; -
使用方法
before(),after()和equals()。例如,一个月的12号比18号早,则new Date(99, 2, 12).before(new Date (99, 2, 18))返回true; -
使用
compareTo()方法,它是由Comparable接口定义的,Date类实现了这个接口。
使用SimpleDateFormat格式化日期
SimpleDateFormat是一个以语言环境敏感的方式来格式化和分析日期的类。SimpleDateFormat允许你选择任何用户自定义日期时间格式来运行。例如:
-
package educoder; -
import java.util.*; -
import java.text.*; -
public class DateDemo { -
public static void main(String args[]) { -
Date dNow = new Date(); -
SimpleDateFormat ft = new SimpleDateFormat( -
"E yyyy.MM.dd 'at' hh:mm:ss a zzz"); -
System.out.println("Current Date: " + ft.format(dNow)); -
} -
} -
SimpleDateFormat ft = new SimpleDateFormat ("E yyyy.MM.dd 'at' hh:mm:ss a zzz");
这一行代码确立了转换的格式,其中yyyy是完整的公元年,MM是月份,dd是日期,hh:mm:ss 是时、分、秒。
注意:有的格式大写,有的格式小写,例如MM是月份,mm是分;HH 是 24 小时制,而 hh 是 12 小时制。
以上实例编译运行结果如下: Current Date: 星期日 2018.08.12 at 11:45:16 下午 CST
日期和时间的格式化编码:
时间模式字符串用来指定时间格式。在此模式中,所有的ASCII字母被保留为模式字母,定义如下:


使用printf格式化日期
printf方法可以很轻松地格式化时间和日期。使用两个字母格式,它以%t开头并且以下面表格中的一个字母结尾。

实例:
-
package educoder; -
import java.util.Date; -
public class DateDemo { -
public static void main(String args[]) { -
// 初始化 Date 对象 -
Date date = new Date(); -
// c的使用 -
System.out.printf("全部日期和时间信息:%tc%n", date); -
// f的使用 -
System.out.printf("年-月-日格式:%tF%n", date); -
// d的使用 -
System.out.printf("月/日/年格式:%tD%n", date); -
// r的使用 -
System.out.printf("HH:MM:SS PM格式(12时制):%tr%n", date); -
// t的使用 -
System.out.printf("HH:MM:SS格式(24时制):%tT%n", date); -
// R的使用 -
System.out.printf("HH:MM格式(24时制):%tR", date); -
} -
}
输出结果: 全部日期和时间信息:星期日 八月 12 23:51:03 CST 2018 年-月-日格式:2018-08-12 月/日/年格式:08/12/18 HH:MM:SS PM格式(12时制):11:51:03 下午 HH:MM:SS 格式(24时制):23:51:03 HH:MM 格式(24时制):23:51
如果你需要重复提供日期,那么利用这种方式来格式化它的每一部分就有点复杂了。因此,可以利用一个格式化字符串指出要被格式化的参数的索引。
索引必须紧跟在%后面,而且必须以$结束。例如:
-
package educoder; -
import java.util.Date; -
public class DateDemo { -
public static void main(String args[]) { -
// 初始化 Date 对象 -
Date date = new Date(); -
// 使用toString()显示日期和时间 -
System.out.printf("%1$s %2$tB %2$td, %2$tY", "Due date:", date); -
} -
}
输出结果: Due date: 八月 12, 2018
或者,你可以使用<标志。它表明先前被格式化的参数要被再次使用。例如:
-
package educoder; -
import java.util.Date; -
public class DateDemo { -
public static void main(String args[]) { -
// 初始化 Date 对象 -
Date date = new Date(); -
// 显示格式化时间 -
System.out.printf("%s %tB %<te, %<tY", "Due date:", date); -
} -
}
输出结果: Due date: 八月 12, 2018
定义日期格式的转换符可以使日期通过指定的转换符生成新字符串。这些日期转换符如下所示:
-
package educoder; -
import java.util.Date; -
import java.util.Locale; -
public class DateDemo { -
public static void main(String args[]) { -
Date date = new Date(); -
// b的使用,月份简称 -
String str = String.format(Locale.US, "英文月份简称:%tb", date); -
System.out.println(str); -
System.out.printf("本地月份简称:%tb%n", date); -
// B的使用,月份全称 -
str = String.format(Locale.US, "英文月份全称:%tB", date); -
System.out.println(str); -
System.out.printf("本地月份全称:%tB%n", date); -
// a的使用,星期简称 -
str = String.format(Locale.US, "英文星期的简称:%ta", date); -
System.out.println(str); -
// A的使用,星期全称 -
System.out.printf("本地星期的简称:%tA%n", date); -
// C的使用,年前两位 -
System.out.printf("年的前两位数字(不足两位前面补0):%tC%n", date); -
// y的使用,年后两位 -
System.out.printf("年的后两位数字(不足两位前面补0):%ty%n", date); -
// j的使用,一年的天数 -
System.out.printf("一年中的天数(即年的第几天):%tj%n", date); -
// m的使用,月份 -
System.out.printf("两位数字的月份(不足两位前面补0):%tm%n", date); -
// d的使用,日(二位,不够补零) -
System.out.printf("两位数字的日(不足两位前面补0):%td%n", date); -
// e的使用,日(一位不补零) -
System.out.printf("月份的日(前面不补0):%te", date); -
} -
}
输出结果: 英文月份简称:Aug 本地月份简称:八月 英文月份全称:August 本地月份全称:八月 英文星期的简称:Sun 本地星期的简称:星期日 年的前两位数字(不足两位前面补0):20 年的后两位数字(不足两位前面补0):18 一年中的天数(即年的第几天):224 两位数字的月份(不足两位前面补0):08 两位数字的日(不足两位前面补0):12 月份的日(前面不补0):12
解析字符串为时间:
SimpleDateFormat类有一些附加的方法,特别是parse(),它试图按照给定的SimpleDateFormat对象的格式化存储来解析字符串。例如:
-
package educoder; -
import java.text.ParseException; -
import java.text.SimpleDateFormat; -
import java.util.Date; -
public class DateDemo { -
public static void main(String args[]) { -
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd"); -
String input = args.length == 0 ? "1818-11-11" : args[0]; -
System.out.print(input + " Parses as "); -
Date t; -
try { -
t = ft.parse(input); -
System.out.println(t); -
} catch (ParseException e) { -
System.out.println("Unparseable using " + ft); -
} -
} -
}
输出结果: 1818-11-11 Parses as Wed Nov 11 00:00:00 CST 1818 Java休眠(sleep)
sleep()使当前线程进入停滞状态(阻塞当前线程),让出CPU的使用、目的是不让当前线程独自霸占该进程所获的CPU资源,以留一定时间给其他线程执行的机会。
你可以让程序休眠一毫秒的时间或者到您的计算机的寿命长的任意段时间。例如,下面的程序会休眠3秒:
-
package educoder; -
import java.util.*; -
public class SleepDemo { -
public static void main(String args[]) { -
try { -
System.out.println(new Date() + "\n"); -
Thread.sleep(1000 * 3); // 休眠3秒 -
System.out.println(new Date() + "\n"); -
} catch (Exception e) { -
System.out.println("Got an exception!"); -
} -
} -
}
输出结果: Mon Aug 13 00:05:33 CST 2018
Mon Aug 13 00:05:36 CST 2018
测量时间:
下面的一个例子表明如何测量时间间隔(以毫秒为单位):
-
package educoder; -
import java.util.Date; -
public class DiffDemo { -
public static void main(String args[]) { -
try { -
long start = System.currentTimeMillis(); -
System.out.println(new Date() + "\n"); -
Thread.sleep(5 * 60 * 10); -
System.out.println(new Date() + "\n"); -
long end = System.currentTimeMillis(); -
long diff = end - start; -
System.out.println("Difference is : " + diff); -
} catch (Exception e) { -
System.out.println("Got an exception!"); -
} -
} -
}
输出结果: Mon Aug 13 00:07:58 CST 2018
Mon Aug 13 00:08:01 CST 2018
Difference is : 3021
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
测试输入: 1999-09-01 预期输出: 你的出生日期距离2020年10月1日:7701天
开始你的任务吧,祝你成功!
package case5;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class DateTest {
public static void main(String[] args) throws ParseException {
// 键盘录入你的出生年月日 格式为yyyy-MM-dd
// 把该字符串转换为一个日期
// 通过该日期得到一个毫秒值
// 获取2020年10月1日的毫秒值
// 两者想减得到一个毫秒值
// 把该毫秒值转换为天 打印输出
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
/********* Begin *********/
SimpleDateFormat ft=new SimpleDateFormat("yyyy-MM-dd");
Date a1=new Date();
Date a2=new Date();
a1=ft.parse(line);
a2=ft.parse("2020-10-01");
long g=a2.getTime()-a1.getTime();
System.out.println("你的出生日期距离2020年10月1日:"+(g/1000/3600/24)+"天");
/********* End *********/
}
}
第6关:Math类
任务描述
本关任务:掌握Math类和Math类中的部分方法。
相关知识
为了完成本关任务,你需要掌握:
1.Math类;
2.Math类中常用方法。
Math类
Math类是一个工具类,它的构造器被定义成private的,因此无法创造Math类的对象。Math类中所有的方法都是类方法,可以直接通过类名来调用他们。
Math类包含完成基本数学函数所需的方法。这些方法基本可以分为三类:三角函数方法、指数函数方法和服务方法。在Math类中定义了PI和E两个double型常量,PI就是π的值,而E即e指数底的值,分别是:3.141592653589793和2.718281828459045。
Math类中常用方法
三角函数方法;
Math类包含下面的三角函数方法:
Math.toDegrees
这个方法是将-π/2到π/2之间的弧度值转化为度,例如:Math.toDegrees(Math.PI/2)结果为90.0;
Math.toRadians
这个方法是将度转化为-π/2到π/2之间的弧度值,例如:Math.toRadians(30)结果为π/6;
Math.sin、Math.cos、Math.tan这三个方法是三角函数中的正弦、余弦和正切,反之Math.asin、Math.acos、Math.atan是他们的反函数。
指数函数方法;
Math类中有五个与指数函数相关的方法Math.exp(a)方法主要是获得以 e 为底 a 为指数的数值;Math.log()和Math.log10()是对数函数;Math.pow(a,b)是以a为底b为指数的值;Math.sqrt() 是开根号。
取整方法;
Math类里包含五个取整方法:Math.ceil()方法是往大里取值;Math.floor()方法是往小里取值;Math.rint()方法返回与参数最接近的整数,返回类型为double,注意.5的时候会取偶数;Math.round()方法分两种:int型和long型,Math.round(a)就是Math.floor(a+0.5),即将原来的数字加上0.5后再向下取整,所以,Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11。
min、max和abs方法
取最大值和最小值以及绝对值。
random方法。
生成随机数取值范围是0.0到1.0的double型数值。也可以用简单的表达式生成任意范围的随机数,例如:
(int)(Math.random()*10) 返回0到9之间的一个随机整数。
接下来通过一个具体的实例进一步了解Math类的常用方法:
package educoder;
public class MathTest{
public static void main(String args[]){
/**
*Math.sqrt()//计算平方根
*Math.cbrt()//计算立方根
*Math.pow(a, b)//计算a的b次方
*Math.max( , );//计算最大值
*Math.min( , );//计算最小值
*/
System.out.println(Math.sqrt(16)); //4.0
System.out.println(Math.cbrt(8)); //2.0
System.out.println(Math.pow(3,2)); //9.0
System.out.println(Math.max(2.3,4.5));//4.5
System.out.println(Math.min(2.3,4.5));//2.3
/**
* abs求绝对值
*/
System.out.println(Math.abs(-10.4)); //10.4
System.out.println(Math.abs(10.1)); //10.1
/**
* ceil天花板的意思,就是返回大的值
*/
System.out.println(Math.ceil(-10.1)); //-10.0
System.out.println(Math.ceil(10.7)); //11.0
System.out.println(Math.ceil(-0.7)); //-0.0
System.out.println(Math.ceil(0.0)); //0.0
System.out.println(Math.ceil(-0.0)); //-0.0
System.out.println(Math.ceil(-1.7)); //-1.0
/**
* floor地板的意思,就是返回小的值
*/
System.out.println(Math.floor(-10.1)); //-11.0
System.out.println(Math.floor(10.7)); //10.0
System.out.println(Math.floor(-0.7)); //-1.0
System.out.println(Math.floor(0.0)); //0.0
System.out.println(Math.floor(-0.0)); //-0.0
/**
* random 取得一个大于或者等于0.0小于不等于1.0的随机数
*/
System.out.println(Math.random()); //小于1大于0的double类型的数
System.out.println(Math.random()*2);//大于0小于1的double类型的数
System.out.println(Math.random()*2+1);//大于1小于2的double类型的数
/**
* rint 四舍五入,返回double值
* 注意.5的时候会取偶数
*/
System.out.println(Math.rint(10.1)); //10.0
System.out.println(Math.rint(10.7)); //11.0
System.out.println(Math.rint(11.5)); //12.0
System.out.println(Math.rint(10.5)); //10.0
System.out.println(Math.rint(10.51)); //11.0
System.out.println(Math.rint(-10.5)); //-10.0
System.out.println(Math.rint(-11.5)); //-12.0
System.out.println(Math.rint(-10.51)); //-11.0
System.out.println(Math.rint(-10.6)); //-11.0
System.out.println(Math.rint(-10.2)); //-10.0
/**
* round 四舍五入,float时返回int值,double时返回long值
*/
System.out.println(Math.round(10.1)); //10
System.out.println(Math.round(10.7)); //11
System.out.println(Math.round(10.5)); //11
System.out.println(Math.round(10.51)); //11
System.out.println(Math.round(-10.5)); //-10
System.out.println(Math.round(-10.51)); //-11
System.out.println(Math.round(-10.6)); //-11
System.out.println(Math.round(-10.2)); //-10
}
}
输出结果:
4.0
2.0
9.0
4.5
2.3
10.4
10.1
-10.0
11.0
-0.0
0.0
-0.0
-1.0
-11.0
10.0
-1.0
0.0
-0.0
0.6148102966002477
0.026175344383210897
2.2298232345361297
10.0
11.0
12.0
10.0
11.0
-10.0
-12.0
-11.0
-11.0
-10.0
10
11
11
11
-10
-11
-11
-10
编程要求
请仔细阅读右侧代码,根据方法内的提示,在Begin - End区域内进行代码补充,具体任务如下:
编写测试类MathTest,输入4个int类型数值,7个double类型数值;
分别输出第一个数的平方根,第二个数的立方根,第三个数的第四个数次方,第五个数和第六个数的最大值、最小值,第七个数的绝对值,第八个数的ceil值,第九个数的floor值,第十个数的rint值,第十一个数的round值。
测试说明
补充完代码后,点击测评,平台会对你编写的代码进行测试,当你的结果与预期输出一致时,即为通过。
测试输入:
25
27
4
3
3.5
5.5
-8.8
10.8
9.6
10.62
11.51
预期输出:
5.0
3.0
64.0
5.5
3.5
8.8
11.0
9.0
11.0
12
开始你的任务吧,祝你成功!
package case6;
import java.util.Scanner;
import java.lang.Math;
public class MathTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int a1 = sc.nextInt();
int a2 = sc.nextInt();
int a3 = sc.nextInt();
int a4 = sc.nextInt();
double a5 = sc.nextDouble();
double a6 = sc.nextDouble();
double a7 = sc.nextDouble();
double a8 = sc.nextDouble();
double a9 = sc.nextDouble();
double a10 = sc.nextDouble();
double a11 = sc.nextDouble();
/********* Begin *********/
System.out.println(Math.sqrt(a1));
System.out.println(Math.cbrt(a2));
System.out.println(Math.pow(a3,a4));
System.out.println(Math.max(a5,a6));
System.out.println(Math.min(a5,a6));
System.out.println(Math.abs(a7));
System.out.println(Math.ceil(a8));
System.out.println(Math.floor(a9));
System.out.println(Math.rint(a10));
System.out.println(Math.round(a11));
/********* End *********/
}
}
Java开发的就业市场正在经历结构性调整,竞争日益激烈
传统纯业务开发岗位(如仅完成增删改查业务的后端工程师)的需求,特别是入门级岗位,正显著萎缩。随着企业技术需求升级,市场对Java人才的要求已从通用技能转向了更深入的领域经验(如云原生、微服务)或前沿的AI集成能力。这也导致岗位竞争加剧,在一、二线城市,求职者不仅面临技术内卷,还需应对学历与项目经验的高门槛。
大模型为核心的AI领域正展现出前所未有的就业热度与人才红利
2025年,AI相关新发岗位数量同比激增543%,单月增幅最高超过11倍,大模型算法工程师位居热门岗位前列。行业顶尖人才的供需严重失衡,议价能力极强,跳槽薪资涨幅可达30%-50%。值得注意的是,市场并非单纯青睐算法研究员,而是急需能将大模型能力落地于复杂业务系统的工程人才。这使得具备企业级架构思维和复杂系统整合经验的Java工程师,在向“Java+大模型”复合人才转型时拥有独特优势,成为企业竞相争夺的对象,其薪资天花板也远高于传统Java岗位。

说真的,这两年看着身边一个个搞Java、C++、前端、数据、架构的开始卷大模型,挺唏嘘的。大家最开始都是写接口、搞Spring Boot、连数据库、配Redis,稳稳当当过日子。
结果GPT、DeepSeek火了之后,整条线上的人都开始有点慌了,大家都在想:“我是不是要学大模型,不然这饭碗还能保多久?”
先给出最直接的答案:一定要把现有的技术和大模型结合起来,而不是抛弃你们现有技术!掌握AI能力的Java工程师比纯Java岗要吃香的多。
即使现在裁员、降薪、团队解散的比比皆是……但后续的趋势一定是AI应用落地!大模型方向才是实现职业升级、提升薪资待遇的绝佳机遇!
如何学习AGI大模型?
作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
2025最新版CSDN大礼包:《AGI大模型学习资源包》免费分享**
一、2025最新大模型学习路线
一个明确的学习路线可以帮助新人了解从哪里开始,按照什么顺序学习,以及需要掌握哪些知识点。大模型领域涉及的知识点非常广泛,没有明确的学习路线可能会导致新人感到迷茫,不知道应该专注于哪些内容。
我们把学习路线分成L1到L4四个阶段,一步步带你从入门到进阶,从理论到实战。

L1级别:AI大模型时代的华丽登场
L1阶段:我们会去了解大模型的基础知识,以及大模型在各个行业的应用和分析;学习理解大模型的核心原理,关键技术,以及大模型应用场景;通过理论原理结合多个项目实战,从提示工程基础到提示工程进阶,掌握Prompt提示工程。

L2级别:AI大模型RAG应用开发工程
L2阶段是我们的AI大模型RAG应用开发工程,我们会去学习RAG检索增强生成:包括Naive RAG、Advanced-RAG以及RAG性能评估,还有GraphRAG在内的多个RAG热门项目的分析。

L3级别:大模型Agent应用架构进阶实践
L3阶段:大模型Agent应用架构进阶实现,我们会去学习LangChain、 LIamaIndex框架,也会学习到AutoGPT、 MetaGPT等多Agent系统,打造我们自己的Agent智能体;同时还可以学习到包括Coze、Dify在内的可视化工具的使用。

L4级别:大模型微调与私有化部署
L4阶段:大模型的微调和私有化部署,我们会更加深入的探讨Transformer架构,学习大模型的微调技术,利用DeepSpeed、Lamam Factory等工具快速进行模型微调;并通过Ollama、vLLM等推理部署框架,实现模型的快速部署。

整个大模型学习路线L1主要是对大模型的理论基础、生态以及提示词他的一个学习掌握;而L3 L4更多的是通过项目实战来掌握大模型的应用开发,针对以上大模型的学习路线我们也整理了对应的学习视频教程,和配套的学习资料。
二、大模型经典PDF书籍
书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础。(书籍含电子版PDF)

三、大模型视频教程
对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识。

四、大模型项目实战
学以致用 ,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。

五、大模型面试题
面试不仅是技术的较量,更需要充分的准备。
在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。

因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取


1万+

被折叠的 条评论
为什么被折叠?



