public class DemoVariable03{
public static void main(String[] args){
/*
声明两个变量 a,b ,a = 10,b=20 ,输出这两个变量,
输出内容是 : a的值是 :xx ,b的值是:xx
然后将a和b的值做交换,再分别输出a和b
*/
int a = 10;
int b = 20;
System.out.println("a的值是:" + a);
System.out.println("b的值是:" + b);
//借助一个中间变量
int c;
c = a; //先把a赋值给c
a = b; //再把b赋值给a
b = c; //再把c赋值给b
System.out.println("a的值是:" + a);
System.out.println("b的值是:" + b);
}
}
3.5 类型转换(大类型&小类型、int&char的转换)
大类型和小类型:大小类型的区分即是他们的取值范围的大小
byte、 short、 int 、long、 float、 double
大小数据类型的转换:小类型->大类型 : 隐式的数据转换,一定是安全的
大类型 -> 小类型 : 显示的数据类型转换
语法: 小类型 = (小类型) 大类型值;
public class DemoVariable04{
public static void main(String[] args){
//隐式的数据类型转换,小类型 -> 大类型
byte b = 100;
int i = b;
System.out.println(i);
//小类型向大类型转换的时候,会产生精度丢失问题
float f1 = 2.58F;
double d1 = f1; // 2.5799999237060547
System.out.println(d1);
int num = 1234;
float f2 = num;
System.out.println(f2);
//byte类型或者short类型,如果做运算,会被提升类型为int,结果需要做强制转换
byte b1 = 50;
byte b2 = 50;
int b3 = b1 + b2; //byte + byte => int + int
byte b4 = (byte)(b1 + b2);
System.out.println(b3);
System.out.println(b4);
//显示的数据类型转换, 大 -> 小
int num01 = 100;
byte num02 = (byte)num01;
System.out.println(num02);
//大类型的值,转为小类型,需要强制转换,
//如果超过了小类型的范围,可以转换成功,但是最终的结果会发生改变
int num03 = 200;
byte num04 = (byte)num03;
System.out.println(num04); //-56
double num05 = 2.56;
float f3 = (float)num05;
System.out.println(f3);
int num06 = (int)num05;
System.out.println(num06); //2
//字符
char ch01 = 'a';
System.out.println(ch01 + 1); //98
float f4 = (float)2.56; //通过将double类型 2.56强转为float
float f5 = 2.56f; //声明的时候,直接声明为float类型
}
}
4 运算符
4.1 算术运算符
1 表达式:
指的是用运算符连接起来的的式子,比如:a+b,a>3.
2 一元运算符:
只需要一个数据就可以进行操作的运算符。例如:自增++,自减--,-负号
++ :表示让某个值自身加1
-- :表示让某个值自身减1
++和-- 可以写在变量之前,或者写在变量之后,写法:a++或者++a
++在前面和在后面的区别:
如果是自身的运算,结果上是没有区别的。
如果是做混合计算,存在区别
a++ ,先将a参与表达式运算,然后再给自身加1
++a,先给自身加1,然后再参与表达式的运算
int a = 10;
int b = a++;
int c = --b;
int d = ++c + b++;
System.out.println( a + "--" + b + "--" + c + "--" + d);
4.2 二元运算符
二元运算符:需要两个数据才可以进行操作的运算符。例如:加法+、赋值=
四则运算 :+ - * /
求余 :%
加法 : +
如果是数字类型使用+,那么就是求和。
如果是char类型使用+,那么会将char转为对应的数值(ascii码值)参与计算。
如果是字符串类型使用+,那么会将后面的内容,拼接到字符串的后面。
减法:- 没有特殊的用法,用来给数值求差值
乘法:* 用来给数值求乘积的
除法:/ ,用来给数值求商,整数参与运算后,会将结果的小数部分省略,保留整数部分
求余:% , 用来求两个数值之间的余数
int a = 10;
int b = a++;
int c = --b;
int d = ++c+b++;
System.out.println(a+"--"+b+"--"+c+"--"+d);
//数字类型使用
System.out.println(a + b);
//char类型使用
System.out.println('a' + b);
//字符串:把后面的值拼接到字符串的后面
System.out.println("100" + 10);
System.out.println(100 / 3); //取整
System.out.println(2.55 / 1.2); //仍是浮点数
练习 :
有一个五位数的数字,12345 ,希望这个数字和 10 做运算,得出这个5位数的 个十百千万位的值
int number = 12345;
int unit = number % 10; // 个位
int ten = (number / 10) % 10; // 十位
int hundred = (number / 100) % 10; // 百位
int thousand = (number / 1000) % 10; // 千位
int tenThousand = (number / 10000) % 10; // 万位
System.out.println("个位:" + unit);
System.out.println("十位:" + ten);
System.out.println("百位:" + hundred);
System.out.println("千位:" + thousand);
System.out.println("万位:" + tenThousand);
public class Demo5 {
public static void main(String[] args) {
//赋值运算符
//+= -= *= /= %=
//a += 2; 表示 a = a + 2;
int a = 10;
a += 5; // a = a + 5; =左边的a,表示a这个变量名, =右边的a,表示找上面的a变量带入到这里
System.out.println(a); //15
a -= 5; // a = a - 5;
System.out.println(a); // 10
a *= 5; // a = a * 5
System.out.println(a); // 50
a /= 5; //a = a/5;
System.out.println(a); //10
a %= 3; //a = a%3;
System.out.println(a);//1
}
}
4.8 三元运算符(三目运算符):嵌套使用
语法 : 变量 = 表达式 ? 值1 : 值2;
如果前面的表达式的结果是true,最终的变量的结果就是值1,如果是false,变量的结果就是值2
public class Demo6 {
public static void main(String[] args) {
//三元运算符
//声明一个变量a = 10, 声明一个变量b,如果a > 20 ,那么b 的值就等于a,否则b的值就等于20
int a = 10;
int b;
b = a > 20 ? a : 20;
System.out.println(b);
//价格的计算,如果购买物品价格超过了500,那么结算总价就打9折,否则就按原价结算
int price = 600;
double total = price > 500 ? price * 0.9 : price;
System.out.println(total);
//定义 x = 10, y = 20 ,z = 30 ,使用三元表达式,找出abc中的最大值
int x = 10,y = 20, z = 30;
int max = x > y ? x : y;
max = max > z ? max : z;
System.out.println(max);
max = (x > y ? x : y) > z ? (x > y ? x : y) : z;
System.out.println(max);
max = 0 ;
max = (x > y ? x : max) > z ? max : z;
System.out.println("最大值:" + max);
}
}
4.9 Scanner(键盘录入)
Scanner 是一个类,这个类是由系统写好了,提供给我们使用的
我们在使用的时候,需要去把这个类的包导入进来,然后就可以使用它了
使用步骤 :
1,导包
import java.util.Scanner;
2,创建对象
Scanner sc = new Scanner(System.in);
3,使用对象scanner调用方法,并把输入的值赋值给变量
int a = scanner.nextInt();
package com.iweb.airui369.day02.operator;
import java.util.Scanner;
public class Demo07 {
public static void main(String[] args) {
//创建Scanner类的对象(变量)
//语法 : 类型 变量名 = 值;
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个数字a:");
//使用对象scanner调用方法,并把输入的值赋值给变量
int a = scanner.nextInt();
System.out.println("请输入一个数字b:");
//使用对象scanner调用方法,并把输入的值赋值给变量
int b = scanner.nextInt();
System.out.println("输入的两个数字的和是:" + (a + b));
}
}
public class DemoSwitch {
public static void main(String[] args) {
//接收用户输入的数字(1-5),返回对应可以做的事情
//1,查询所有用户 2,增加用户 3,删除用户 4,修改用户 5,查询单个用户
Scanner scanner = new Scanner(System.in);
System.out.println("请输入数字1-5,选择对应的操作:");
int num = scanner.nextInt();
//通过switch去判断
switch (num){
case 1:
System.out.println("查询所有用户!");
break;
case 2:
System.out.println("增加用户!");
break;
case 3:
System.out.println("删除用户!");
break;
case 4:
System.out.println("修改用户!");
break;
case 5:
System.out.println("查询单个用户!");
break;
default:
System.out.println("你输入的内容不正确!");
}
}
}
//do-while循环的用法
public class Demo02 {
public static void main(String[] args) {
//使用do-while输出1-10
int i = 1;
do{
System.out.println(i);
i++;
}while (i <= 10);
//使用do-while完成1-100之间的偶数的求和
int sum = 0;
int a =0;
do {
sum += a;
a += 2;
}while (a <= 100);
System.out.println(sum);
}
}
5.4.3 for循环
语法 :
for(初始化语句a;判断条件语句b;控制条件语句c){
代码块;
}
执行流程 :
先执行初始化语句a
执行判断条件b,如果b的结果为true,执行代码块内容如果b的结果为false,循环结束
执行控制条件c
再执行b,依次循环
public class Demo03 {
public static void main(String[] args) {
//声明for循环 ,从1输出到10
for (int i = 1;i <= 10; i++){
System.out.println(i);
}
//使用for循环来求1-100的和
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
System.out.println(sum);
//求1-100的偶数和
int sum1 = 0;
for (int i = 0; i <= 100; i++) {
if (i % 2 == 0){
sum1 += i;
}
}
System.out.println("1-100的偶数和为:" + sum1);
//输出所有的水仙花数
//水仙花数是一个三位数,特点是 :
//个位的三次方+十位的三次方+百位的三次方 的和 等于这个数字本身
for (int i = 100; i < 1000; i++) {
//个位的三次方+十位的三次方+百位的三次方的和
int ge = i % 10;
int shi = i / 10 % 10;
int bai = i / 100;
if (i == ge*ge*ge + shi*shi*shi + bai*bai*bai){
System.out.println("水仙花数:" + i);
}
}
}
}
for循环的嵌套使用:
public class Demo04 {
public static void main(String[] args) {
/*
******
******
******
******
*/
//System.out.print("*");
//System.out.print("*");
//System.out.print("*");
//System.out.print("*");
//System.out.print("*");
//System.out.println("*");
//for (int i = 0; i < 6; i++) {
// System.out.print("*");
//}
//System.out.println();
//for (int i = 0; i < 6; i++) {
// System.out.print("*");
//}
//System.out.println();
//for (int i = 0; i < 6; i++) {
// System.out.print("*");
//}
for (int i = 0; i < 4; i++) { //外层循环,控制行
for (int j = 0; j < 6; j++) { //内层的循环,控制列
System.out.print("*");
}
System.out.println();
}
//使用for循环嵌套,完成一个乘法口诀表的编写
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i ; j++) {
System.out.print(j + "*" + i + "=" + (i*j)+ " ");
}
System.out.println();
}
}
}
5.4.4 break、continue、return的区别
break 只用在switch和循环中
continue一般用在循环中,表示跳出当次循环,继续下次循环
return用在方法中的,一般用来结束方法
5.4.4.1 Break用法
/*
break在多重循环中的使用
*/
public class BreakDemo {
public static void main(String[] args) {
wc:for (int i = 0; i < 5; i++) {
nc:for (int j = 0; j < 4; j++) {
if (j == 2){
// break; //默认状态下,跳出内部循环
// break wc;
break nc;
}
System.out.print("*");
}
System.out.println();
}
}
}
5.4.4.2 Continue用法
/*
continue的用法
*/
public class ContinueDemo {
public static void main(String[] args) {
//有10个学生,循环录入学生的成绩,录完之后,统计
//80分以上的学生的占比情况
//1,创建需要的变量,输入对象
double count = 0.0;
Scanner scanner = new Scanner(System.in);
//2,写一个循环,循环10次,每次循环录入一个学生成绩
for (int i = 1; i <= 10; i++) {
//3,录入成绩后,可以判断这个学生的成绩是否超过80
System.out.println("请输入" + i +"号学生的成绩:");
int score = scanner.nextInt();
//4,如果超过80,记录到一个变量,不超过 continue
if (score < 80){
continue;
}
count++;
}
double total = count / 10;
//5,计算占比
System.out.println("超过80分的学生占比为:" + total * 100 +"%");
}
}
5.4.4.3 return的用法:用来结束方法的,不是用来结束循环的
public class ReturnDemo {
public static void main(String[] args) {
for (int i = 1; i < 10; i++) {
if (i == 5){
System.out.println("退出");
//break;
//continue;
return;
}
System.out.println(i);
}
System.out.println("运行结束");
}
// 1 2 3 4 退出 运行结束
// 1 2 3 4 退出 6 7 8 9 运行结束
//1 2 3 4 退出
}
public class MethodDemo {
//写一个方法,调用之后,可以传入2个整数,并完成两个整数的计算求和后返回
public static int add(int a,int b){
int sum = a + b; //拿到传入的参数,并计算和
return sum; //把求和的结果返回
}
public static void main(String[] args) {
//调用方法,
//也可以将整个方法的表达式参与运算
System.out.println(add(10, 20));
// 可以声明一个变量,接收返回的值
int result = add(10,20);
System.out.println(result);
}
}
public static void swap(int a , int b){
System.out.println("传入的参数为 a = " + a + " ,b = " + b);
int c = a;
a = b;
b = c;
System.out.println("交换之后的 a = " + a + " ,b = " + b);
}
//方法递归的使用
public class MethodDemo03 {
public static void main(String[] args) {
//方法递归
//method01();
int sum = sum01(100);
System.out.println(sum);
int sum02 = sum02(100);
System.out.println(sum02);
}
//public static void method01(){
// int i = 1;
// System.out.println(++i);
// method01();
//}
//定义一个方法,传入参数n,可以返回1-n之间数值的和
//普通循环求法
public static int sum01(int n){
int sum = 0;
for (int i = 0; i <= n; i++) {
sum += i;
}
return sum;
}
//递归的写法 1+2+3+4+5+...+n
public static int sum02(int n){
if (n == 1){
return 1;
}
return n + sum02(n-1);
}
// n = 1 sum = 1
// n = 2 2 + sum02(1) ==> 2 + 1
// n = 3 3 + sum02(2) => 3 + 2 + 1
//..
}
习题:一只青蛙一次可以跳上1级台阶,也可以跳上2级。
求该青蛙跳上一个 n 级的台阶总共有多少种跳法(先后次序不同算不同的结果)
public class MethodDem04 {
//一只青蛙一次可以跳上1级台阶,也可以跳上2级。
// 求该青蛙跳上一个 n 级的台阶总共有多少种跳法(先后次序不同算不同的结果)
//1 1 1
//2 2 1+1 2
//3 3 1+1+1 1+2 2+1
//4 5 1+1+1+1 1+1+2 1+2+1 2+1+1 2+2
//5 8 1+1+1+1+1 1+1+1+2 1+1+2+1 1+2+1+1 2+1+1+1 2+2+1 2+1+2 1+2+2
public static int jumpMethod(int n){
if (n == 1 || n == 2){
return n;
}
return jumpMethod(n-1) + jumpMethod(n-2);
}
public static void main(String[] args) {
int i = jumpMethod(10);
System.out.println(i);
}
}
public class QuickSort {
//写一个快速排序的方法
public static void quickSort(int[] arr,int left , int right){
//提前声明需要使用的变量
int i,j,temp,t;
//递归结束条件
if (left > right){
return;
}
//开始排序
i = left;
j = right;
temp = arr[left]; //中间值
//循环判断
while (i < j){
//如果j下标的值,比中间值大,j做--操作
while (temp <= arr[j] && i < j){
j--;
}
//如果i下标的值,比中间值小,i做++操作
while (temp >= arr[i] && i < j){
i++;
}
//如果上面两个条件不满足,i 和 j 交换
if(i < j){
t = arr[j];
arr[j] = arr[i];
arr[i] = t;
}
}
//最后需要将中间值和 j的值做交换
arr[left] = arr[j];
arr[j] = temp;
//递归调用左边
quickSort(arr,left,j-1);
//递归调用右边
quickSort(arr,j+1,right);
}
//输出方法
public static void printArray(int[] arr){
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int[] arr = {10,31,43,2,34,12,4};
System.out.println("排序前");
printArray(arr);
//调用排序方法
quickSort(arr,0,arr.length-1);
System.out.println("排序后");
printArray(arr);
}
}
测试排序时间:
分别插入10万条、100万条数据再做测试
/*
测试排序时间
*/
public class SortTime {
public static void main(String[] args) {
//循环往数组中,存放1万条随机数据
//使用Random类,可以生成随机数
Random random = new Random();
//int i = random.nextInt(100000);//生成随机数
//System.out.println(i);
//声明一个长度为10000的数组
int[] arr = new int[10000];
for (int i = 0; i < arr.length; i++) {
//往数组中存入100000以内的数据
arr[i] = random.nextInt(100000);
}
//System.currentTimeMillis()可以放回当前时间的毫秒值
long start = System.currentTimeMillis();
System.out.println("排序前:");
//调用排序方法
//BubbleSort.bubbleSort(arr);
//InsertSort.insertSort(arr);
//QuickSort.quickSort(arr,0,arr.length-1);
//SelectSort.selectSort(arr);
System.out.println("排序后:");
long end = System.currentTimeMillis();
long time = end - start;
System.out.println("排序时间:" + time);
}
}
public class SearchDemo {
public static void main(String[] args) {
//定义一个数组
int[] arr = {12,34,56,23,11,66,39,36};
//查找39在数组中的什么位置?返回它的下标
//基本查找方式:
int index = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 39){
index = i;
break;
}
}
System.out.println("查找的39的下标:" + index);
}
}
6.3.6 二分查找
二分查找法 :也称为折半查找法,用来查找有序的序列数据
/*
二分查找
*/
public class BinarySearch {
public static void main(String[] args) {
//定义一个有序的数组
int[] arr = {11,22,33,44,55,66,77,88,99};
int index = getIndex(arr, 44);
System.out.println("44的下标是:" + index);
}
//写一个二分查找方法,返回值是 索引值
//参数是 数组和 要查找的值
public static int getIndex(int[] arr,int value){
//定义最小索引、最大索引
int max = arr.length -1 ;
int min = 0;
//计算中间索引
int mid = (max + min) / 2;
//拿查找的值和中间索引值做比较
//如果中间值和查找的值不同,就循环,相同,循环结束
while (value != arr[mid]){
//中间值大 ,往左找
if (arr[mid] > value){
max = mid - 1;
//中间值小,往右找
}else if (arr[mid] < value){
min = mid + 1;
}
//判断,没有找到的情况
if (min > max){
return -1;
}
mid = (max + min) / 2;
}
return mid;
}
}
public class Person {
//属性
String name;
int age;
String gender;
//方法
public void show(){
System.out.println("我是" + name +
",我今年" + age + "岁,我的性别是" + gender);
}
}
public class Person {
//属性
String name;
int age;
String gender;
//方法
public void show(){
System.out.println("我是" + name +
",我今年" + age + "岁,我的性别是" + gender);
}
}
注意 :
1,类对象的创建,可以在类中的main方法中创建,也可以在别的类的main方法中创建
2,类的成员属性或者成员方法,必须要通过这个类的对象才能调用到
7.3 对象的内存图
java文件被编译为.class的字节码文件,字节码文件会进入方法区
运行main方法之后,main方法会先进栈
执行main方法中的代码,从上到下,依次执行
先执行: Person person = new Person(); 会在堆区创建一个区域,将方法区的Person类及其属性方法都会拿过来,成员属性拿过来后有一个默认值,成员方法拿过来后其实是一个引用,指向方法区中的字节码文件中的方法
public class Phone {
//属性
String brand;
String color;
double price;
//构造函数
public Phone(){} //无参
public Phone(String brand,String color,double price){
this.brand = brand;
this.color = color;
this.price = price;
}
//普通方法
public void show(){
System.out.println(brand + "--" + color + "--" + price);
}
}
public class PhoneTest {
public static void main(String[] args) {
//通过无参构造,构造对象
Phone phone = new Phone();
phone.brand = "苹果";
phone.color = "白色";
phone.price = 5999.0;
phone.show();
//通过全参构造
Phone phone1 = new Phone("华为", "银色", 6999.9);
phone1.show();
}
}
7.6 成员方法
成员方法,也称为实例方法,就是将方法声明在类中的成员位置
成员方法的语法,符合之前阶段学习的方法的写法
语法 :
修饰符 返回值类型 方法名(参数列表){
代码块;
return;
}
public class Phone {
//属性
String name;
String color;
double price;
//构造函数
public Phone(){} //无参
public Phone(String brand,String color,double price){
this.name = brand;
this.color = color;
this.price = price;
}
//普通方法
public void show(){
System.out.println(name + "--" + color + "--" + price);
}
//定义一个打电话方法,需要传入一个姓名,完成打电话操作
//输出,使用 xx 品牌手机给xxx打电话
public void call(String name){
System.out.println("使用" + this.name +"手机给" + name + "打电话!");
}
//计算功能 ,计算 两个数字的和 ,有返回值,有参数的方法
public int operator(int a,int b){
return a + b;
}
}
public class PhoneTest {
public static void main(String[] args) {
//通过无参构造,构造对象
Phone phone = new Phone();
phone.name = "苹果";
phone.color = "白色";
phone.price = 5999.0;
phone.show();
phone.call("jack");
//通过全参构造
Phone phone1 = new Phone("华为", "银色", 6999.9);
phone1.show();
//调用成员方法
phone1.call("张三");
int i = phone1.operator(10, 20);
System.out.println(i);
}
}
7.7 参数传递
指的是,在调用方法的时候,传入参数的数据类型的不同,可能会得到不同的结果
方法的参数类型:
总的来说,传入的参数只有两种类型 : 基本数据类型 和 引用数据类型
Java中,参数传递只有一种方式,按值传递
基本类型,就是传递自身的值
引用类型,传递的是对应的地址值,不是对象自身
基本类型值传递
/*
基本类型的值传递
*/
public class Demo01 {
public void change(int a){
a = 100;
}
public static void main(String[] args) {
int a = 200;
Demo01 d = new Demo01();
d.change(a);
System.out.println(a); //200
}
}
对象值传递
public class Demo02 {
public void change(Person person){
person.age = 20;
}
public static void main(String[] args) {
Person person = new Person(); //4554617c
System.out.println(person);
person.age = 10;
System.out.println(person.age);//10
Demo02 demo02 = new Demo02();
//方法参数,是引用类型的话,会将引用地址中的内容改变
demo02.change(person);
System.out.println(person.age); //20
}
}
public class Person {
int age;
}
字符串的值传递
public class Demo03 {
public void change(String str){
str = "hello";
}
//字符串是一个特殊的引用类型,它作为参数传递的时候
//和基本类型的传递方式一致
public static void main(String[] args) {
//String str = "你好";
String str = new String("你好");
System.out.println(str);//你好
Demo03 demo03 = new Demo03();
//将字符类型作为参数传递
demo03.change(str);
System.out.println(str); //你好
}
}
数组的值传递
public class Demo04 {
public void change(int[] arr){
arr[0] = 20;
}
//数组作为参数传递,会改变引用的内容
public static void main(String[] args) {
int arr[] = {10};
System.out.println(arr[0]);//10
Demo04 demo04 = new Demo04();
demo04.change(arr);
System.out.println(arr[0]);//20
}
}
public class Student {
String name; //姓名
String sid; //学号
//构造方法重载
public Student(){
}
public Student(String name){
this.name = name;
}
public Student(String sid,String name){
this.sid = sid;
this.name = name;
}
//普通方法的重载
public void add(int a,double b){
System.out.println(a + b);
}
//类型不同
public int add(int a,int b){
return a+b;
}
//顺序不同
public double add(double b,int a){
return a+b;
}
//个数不同
public int add(int a,int b,int c){
return a+b+c;
}
public static void main(String[] args) {
Student s = new Student("张三");
//调用重载方法
s.add(10,20);
s.add(1,2,3);
}
}
7.9 this关键字
this关键字,表示的是当前对象的意思
this可以用来调用属性、调用方法、调用构造方法
7.9.1 this调用属性
this调用属性的时候,指向的是当前对象
public class Person {
String name;
//和谁聊天的方法
//this表示当前对象的意思,指向方法的当前调用对象
//谁调用,就指向谁
//this在方法中使用的时候,如果方法中存在和属性同名的局部变量
//加上this可以表示指向对象的属性
public void say(String name){
System.out.println(this.name + "和" + name +"正在聊天!");
}
public Person() {
}
//构造方法中的this,在调用属性的时候
//表示,将来通过这个构造方法创建的对象的属性的值就是传入的值
//this就是指向创建的对象
public Person(String name) {
this.name = name;
}
public static void main(String[] args) {
Person p1 = new Person();
p1.name = "张三";
p1.say("王五"); //张三和王五在聊天
Person p2 = new Person();
p2.name = "李四";
p2.say("王五"); //李四和王五在聊天
Person p3 = new Person("张无忌");
Person p4 = new Person("赵敏");
}
}
7.9.2 this调用成员方法
public class Student {
public void say(){
System.out.println("学生在说话!");
}
public void say(String name){
System.out.println("学生在和" + name + "说话");
}
public void sleep(){
say();
//this调用当前类的成员方法的时候,可以省略不写
// this.say();
this.say("张三");
// System.out.println("学生在说话!");
System.out.println("学生在睡觉!");
}
public static void main(String[] args) {
Student s = new Student();
s.sleep();
}
}
7.9.3 this调用构造方法
this调用构造方法的时候,只能在构造方法中的第一行调用
public class Demo01 {
String name;
int age;
public Demo01(){
this("jack"); //调用的是name参数的构造方法
System.out.println("这是无参构造!1");
}
public Demo01(String name) {
this(20); //这个调用的是age参数的构造
System.out.println("这是参数为name的构造方法!2");
}
public Demo01(int age) {
this.show();//调用的 普通方法show
System.out.println("这是参数为age的构造方法!3");
}
public void show(){
//普通方法中,不能通过this调用构造方法
//this("jack");
//普通方法中,创建通过new关键字创建对象是允许的
Student s = new Student();
System.out.println("这是普通方法!4");
}
public static void main(String[] args) {
new Demo01(); //
}
}
public class StaticDemo02 {
//静态代码块
static {
int a = 100;
System.out.println(a);
}
//构造代码块
{
int b = 200;
System.out.println(b);
}
public StaticDemo02(){
System.out.println("构造方法");
}
{
int c = 300;
System.out.println(c);
}
static {
int d = 400;
System.out.println(d);
}
}
public class StaticTest {
public static void main(String[] args) {
{
int e = 500;
System.out.println(e);
}
StaticDemo02 s1 = new StaticDemo02();
//500
//100
//400
//200
//300
//构造方法
System.out.println("----------------------");
StaticDemo02 s2 = new StaticDemo02();
//200
//300
//构造方法
}
}
7.12 继承的定义、继承的好处、如何继承、继承的特征
定义 :
把多个类中,相同的成员提取出来,定义到一个独立的类中。
然后让当前类和独立类之间产生关系,使当前类具有独立类中的成员内容,这种关系,称为继承
有了继承关系后,当前类称为子类,独立类称为父类
写法:
用extends 关键字来实现继承
class 子类名 extends 父类名{}
public class Person {
String name; //姓名
int age; //年龄
String gender; //性别
public void show(){
System.out.println("我的姓名:" + name
+ ",我的年龄:" + age
+ ",我的性别:" + gender);
}
}
public class Student extends Person {
String className; //班级
}
public class Emp extends Person{ //员工类
String deptName; //部门名称
}
public class Test {
public static void main(String[] args) {
Student s1 = new Student();
//调用来自Person中的属性
s1.name = "张三";
s1.age = 20;
s1.gender = "男";
//调用来自Person类中的方法
s1.show();
Emp emp = new Emp();
emp.name = "李四";
emp.age = 30;
emp.gender = "男";
emp.show();
}
}
public class Father {
public void method01(){
System.out.println("这是父类的普通方法");
}
public Father method02(){
return new Father();
}
public void method03(int a,int b){
System.out.println("父类中带参数的方法");
}
public static void method04(){
System.out.println("父类的静态方法");
}
private void method05(){
System.out.println("父类的私有方法");
}
}
public class Son extends Father {
@Override
public void method01() {
System.out.println("这是子类的方法");
}
//子类重写的方法的返回值,可以和父类相同
//或者是父类返回值的子类
@Override
public Son method02() {
return new Son();
}
//@Override //用来标识子类的方法重写了父类方法的
//method03参数和父类的参数不一样,这个方法仍然可以声明
//但是这个时候,它和父类方法没有关系,
// 只是子类自己的一个普通方法
public void method03(int a) {
System.out.println("子类的方法");
}
//@Override
//子类可以声明和父类相同名称的静态方法,
//但是它们之间的关系并不是重写,
//一般子类很少去写和父类同名的静态方法,除非想要将
//父类的静态方法在子类中隐藏
public static void method04(){
System.out.println("子类的静态方法");
}
//@Override
//父类的私有方法不能被子类重写
private void method05(){
System.out.println("子类重写父类的私有方法");
}
}
7.14.1 方法重写的应用
7.14.1.1 equals()方法重写
public class Student {
private int sid; //学号
private String name; //姓名
private String className; //班级
public Student() {
}
public Student(int sid, String name, String className) {
this.sid = sid;
this.name = name;
this.className = className;
}
@Override
public boolean equals(Object obj) {
//如果比较的两个对象,地址值相同,它们就是同一个对象
if (this == obj){
return true;
}
//如果传入的参数,不是一个Student对象,直接返回false
//通过 instanceof 可以判断某个对象是否是指定类的实例
// 用法 : 对象名 instanceof 类
if (!(obj instanceof Student)){
return false;
}
//判断传入的对象的属性和当前对象的属性的值,是否都是相同的
//传入的参数会被当做是Object类型,将传入的参数,转为Student
Student o = (Student) obj;
if (this.sid == o.sid &&
this.name.equals(o.name) &&
this.className.equals(o.className)){
return true;
}
return false;
}
@Override
public String toString() {
return "Student{" +
"sid=" + sid +
", name='" + name + '\'' +
", className='" + className + '\'' +
'}';
}
}
public class StudentTest {
public static void main(String[] args) {
//创建两个相同对象
Student s1 = new Student(10010, "张三", "1班");
Student s2 = new Student(10010, "张三", "1班");
System.out.println(s1);
//使用== 比较引用类型,比较的是地址值,返回false
System.out.println(s1 == s2); //false
//在Object类中,提供了一个equals()方法,用来比较对象之间是否相同的
//将来,如果想比较对象是否相同,那么就得用equals()方法
//两个相同的对象,我们调用equals比较,希望返回true,但是返回false
//这是因为Object类中的equals()方法,底层代码还是== 做比较,
//如果想要equals()方法可以比较对象的具体的属性,就需要重写equals()方法
System.out.println(s1.equals(s2));
}
}
public abstract class Animal {
private String name;
final int age = 20;
public Animal(String name) {
this.name = name;
}
public Animal() {
}
//抽象方法,声明为抽象方法的类,必须是抽象类
// 加上abstract关键字,完成方法和类的声明
public abstract void eat();
public void sleep(){
System.out.println("动物会睡觉!");
}
//抽象类中可以有静态方法
public static void show(){
System.out.println("动物会说话!");
}
}
//子类继承抽象类之后,子类要么是抽象类,要么就要实现父类中的所有抽象方法
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼~");
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃骨头~");
}
}
public class AnimalTest {
public static void main(String[] args) {
Cat cat = new Cat();
cat.eat();
cat.sleep();
cat.show();
Dog dog = new Dog();
dog.eat();
dog.sleep();
dog.show();
//抽象类不能实例化
//Animal animal = new Animal();
//抽象类中可以定义静态方法,也可以通过类名直接调用
Animal.show();
}
}
7.16 多态
多态的概念 :
一个对象,在不同时刻体现出来的不同状态
Java中多态的表示方式 :父类的引用指向子类的对象
父类 对象名 = new 子类();
public class Person {
public void say(){
System.out.println("人类会说话!");
}
public void show(){
System.out.println("这是父类的show方法");
}
}
public class Student extends Person {
@Override
public void show(){
System.out.println("这是子类的show方法");
}
public void show1(){
System.out.println("这是子类特有的show1方法");
}
}
public class PersonTest {
public static void main(String[] args) {
//多态创建Person对象
//父类的引用指向子类的对象
Person person = new Student();
person.say(); //作为父类形态,可以调用父类特有的方法
// person.show1(); //不能调用子类特有的方法
person.show(); // 作为子类形态,可以调用子类重写父类的方法
}
}
7.16.1 多态的特点
前提条件 :
1,有继承或者实现关系
2,有方法的重写
3,有父类或者父接口的引用指向子类对象
多态的分类 :
1,具体类的多态
class Fu{}
class Zi extends Fu{}
Fu f = new Zi();
2,抽象类的多态
abstract class Fu{}
class Zi extends Fu{}
Fu f = new Zi();
3,接口多态
interface Fu{}
class Zi implements Fu{}
Fu f = new Zi();
多态关系中成员访问特点 :
成员变量 : 直接看等号的左边,左边是谁,优先找谁,没有向上找,找不到就报错
编译看左边,运行看左边
成员方法 :先从等号的左边找,左边不存在,就报错,运行的时候看new的是谁,就找谁
编译看左边,运行看右边
构造方法 :子类的构造默认会访问父类构造
多态的好处:
多态可以提高代码的维护性(继承)
多态可以提高代码扩展性(多态体现)
public abstract class Emp {
public abstract void work();
}
public class Teacher extends Emp{
@Override
public void work() {
System.out.println("老师在讲课!");
}
}
public class Assistant extends Emp {
@Override
public void work() {
System.out.println("助教在辅导");
}
}
public class EmpTest {
public static void main(String[] args) {
//没有多态,创建对象,关心的是通过哪个类创建的对象调用的work方法
Teacher emp1 = new Teacher();
emp1.work();
Assistant emp2 = new Assistant();
emp2.work();
//多态的方式创建,关注点是work方法的调用,其他的东西我不关心
Emp emp3 = new Teacher();
emp3.work();
Emp emp4 = new Assistant();
emp4.work();
}
}
public class Animal {
public void eat(){
System.out.println("吃东西!");
}
}
public class Bird extends Animal {
@Override
public void eat() {
System.out.println("鸟儿吃东西!");
}
public void fly(){
System.out.println("鸟儿飞翔!");
}
}
public class Test {
public static void main(String[] args) {
Animal bird = new Bird();
bird.eat();
Bird b = (Bird)bird;
b.fly();
}
}
public class Father {
public int num = 10; //普通的变量
public final int num2 = 20; //常量
public final void test01(){
System.out.println("父类的final方法");
}
}
public class Son extends Father {
String name;
public void show(){
num = 100;
//num2是常量,无法重新赋值
//num2 = 1000;
System.out.println(num);
System.out.println(num2);
}
//子类不能重新父类的final方法
//public void test01(){
// System.out.println("子类的方法");
//}
}
public class Test {
public static void main(String[] args) {
Son son = new Son();
son.show();
final int a = 10; //final修饰的局部变量也是常量
// a = 100; //不能被重新赋值
System.out.println(a);
Son son1 = new Son();
son1.name = "张三";
System.out.println(son1.name);
final Son son2 = new Son();
son2.name = "李四";
System.out.println(son2.name);
//final修饰的引用类型变量,变量中的属性值是可以被改变的
son2.name = "王五";
System.out.println(son2.name);
//final修饰的引用的类型的变量,引用地址无法重新被赋值
//son2 = new Son();
}
//final能不能修饰局部变量?修饰基本类型和引用类型的区别
//final修饰的局部变量也是常量
//final修饰的引用类型变量,变量中的属性值是可以被改变的
//final修饰的引用的类型的变量,引用地址无法重新被赋值
}
public interface Person {
void say();
}
public interface Father extends Person {
//接口中的成员变量只能是常量,即使变量之前没有加final,仍然默认会去添加final
String name = "jack";
//public Father();
//接口中可以有抽象方法
public abstract void playFootBall();
//普通方法,接口中不能有普通方法
// public void method(){
//
// }
//静态方法,接口中可以有静态方法
public static void method01(){
}
//默认方法,接口中可以存在默认方法,使用default修饰的
default void method02(){
}
}
public interface Mother extends Person {
void sing();
}
public class Son implements Father,Mother {
@Override
public void playFootBall() {
System.out.println("儿子会踢球");
}
@Override
public void sing() {
System.out.println("儿子会唱歌");
}
@Override
public void say() {
}
}
public class Test {
public static void main(String[] args) {
Son son = new Son();
son.playFootBall();
son.sing();
//son.name = "tom"; //name是用final修饰的,是常量
System.out.println(son.name);
//new Father(); //接口不能被实例化
}
}
设计一个简单的USB接口:
//usb接口
public interface USBInterface {
void service();
}
/*
U盘类
*/
public class UDisk implements USBInterface {
@Override
public void service() {
System.out.println("连接USB,U盘开始工作!");
}
}
//鼠标类
public class UMouse implements USBInterface {
@Override
public void service() {
System.out.println("鼠标连接上USB接口,开始工作!");
}
}
public class Test {
public static void main(String[] args) {
//多态创建接口对象
USBInterface usb = new UDisk();
usb.service();
USBInterface usb1 = new UMouse();
usb1.service();
}
}
public interface Inner {
void show1();
void show2();
}
public class Outer {
//外部类的成员方法
public void method(){
//这个操作,相当于在创建接口的实现类
//这个实现类,没有名字,称为匿名内部类
//相当于把实现Inner接口的实现类,和实现类的对象都创建了
//完成了4个动作 :
// 1,Inner接口实现类的创建 2,接口方法的重写 3,实现类对象的创建 4,重写方法的调用
/* new Inner(){
//实现接口中的方法
@Override
public void show1() {
System.out.println("匿名内部类重写的show1方法~");
}
@Override
public void show2() {
System.out.println("匿名内部类重写的show2方法~");
}
}.show1();
//接口中有多个方法的话,写实现就得写多次,比较麻烦
new Inner(){
//实现接口中的方法
@Override
public void show1() {
System.out.println("匿名内部类重写的show1方法~");
}
@Override
public void show2() {
System.out.println("匿名内部类重写的show2方法~");
}
}.show2();
*/
//使用多态来改进写法,父接口的引用指向子类的对象
Inner inner = new Inner(){
//实现接口中的方法
@Override
public void show1() {
System.out.println("匿名内部类重写的show1方法~");
}
@Override
public void show2() {
System.out.println("匿名内部类重写的show2方法~");
}
};
inner.show1();
inner.show2();
}
}
public class OuterTest {
public static void main(String[] args) {
Outer outer = new Outer();
outer.method();
}
}
匿名内部类的笔试题:
public interface Inner {
void show();
}
public class Outer {
//等待补齐代码
}
public class OuterTest {
public static void main(String[] args) {
Outer.method().show();
//在后台输出 :"HelloWord!"
}
}
补充代码:
//Outer.method()
//说明存在静态的method()方法
//Outer.method().show() 说明method方法应该返回Inner对象
public static Inner method(){
return new Inner() {
@Override
public void show() {
System.out.println("HelloWorld!");
}
};
}
7.20 设计模式
通过设计模式的完成计算器的使用:
基本代码实现
/*
基本代码实现计算器
*/
public class Demo01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入计算的第一个数字:");
int a = scanner.nextInt();
System.out.println("请输入运算符号:");
String b = scanner.next();
System.out.println("请输入计算的第二个数字:");
int c = scanner.nextInt();
int result = 0;
switch (b){
case "+":
result = a + c;
break;
case "-":
result = a - c;
break;
case "*":
result = a * c;
break;
case "/":
result = a / c;
break;
default:
System.out.println("运算符输入错误!");
return;
}
System.out.println( a + b + c + "=" +result);
}
}
面向对象实现 :
//面向对象实现
public class Operation {
public static int getResult(int a,int b,String operate){
int result = 0;
switch (operate){
case "+":
result = a + b;
break;
case "-":
result = a - b;
break;
case "*":
result = a * b;
break;
case "/":
result = a / b;
break;
default:
System.out.println("运算符输入错误!");
break;
}
return result;
}
}
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入计算的第一个数字:");
int a = scanner.nextInt();
System.out.println("请输入运算符号:");
String b = scanner.next();
System.out.println("请输入计算的第二个数字:");
int c = scanner.nextInt();
int result = Operation.getResult(a, c, b);
System.out.println(result);
}
}
利用设计模式的工厂方法模式:
//计算类抽象类
public abstract class Operation {
private double num1;
private double num2;
public abstract double getResult();
public double getNum1() {
return num1;
}
public void setNum1(double num1) {
this.num1 = num1;
}
public double getNum2() {
return num2;
}
public void setNum2(double num2) {
this.num2 = num2;
}
}
//加法类
public class Add extends Operation {
@Override
public double getResult() {
return getNum1() + getNum2();
}
}
//减法类
public class Minus extends Operation {
@Override
public double getResult() {
return getNum1() - getNum2();
}
}
//运算工厂类
public class OperationFactory {
public static Operation createOperation(String operate){
if (operate.equals("+")){
return new Add();
}else if (operate.equals("-")){
return new Minus();
}
return null;
}
}
//测试类
public class Test {
public static void main(String[] args) {
Operation o = OperationFactory.createOperation("+");
o.setNum1(10);
o.setNum2(20);
System.out.println(o.getResult());
}
}
利用设计模式的抽象工厂模式:
//计算类抽象类
public abstract class Operation {
private double num1;
private double num2;
public abstract double getResult();
public double getNum1() {
return num1;
}
public void setNum1(double num1) {
this.num1 = num1;
}
public double getNum2() {
return num2;
}
public void setNum2(double num2) {
this.num2 = num2;
}
}
//加法类
public class Add extends Operation {
@Override
public double getResult() {
return getNum1() + getNum2();
}
}
//减法类
public class Minus extends Operation {
@Override
public double getResult() {
return getNum1() - getNum2();
}
}
//计算工厂抽象类
public abstract class OperationFactory {
public abstract Operation createOperation();
}
//加法工厂
public class AddFactory extends OperationFactory {
@Override
public Operation createOperation() {
return new Add();
}
}
//减法工厂
public class MinusFactory extends OperationFactory {
@Override
public Operation createOperation() {
return new Minus();
}
}
//测试类
public class Test {
public static void main(String[] args) {
AddFactory addFactory = new AddFactory();
Operation operation = addFactory.createOperation();
operation.setNum1(10);
operation.setNum2(20);
System.out.println(operation.getResult());
}
}
使用抽象工厂之后,添加一个运算,只要在写子类继承即可:
比如,加个乘法类:
//乘法类
public class ChengFa extends Operation {
@Override
public double getResult() {
return getNum1() * getNum2();
}
}
//乘法工厂
public class ChengFaFactory extends OperationFactory {
@Override
public Operation createOperation() {
return new ChengFa();
}
}
//测试类
ChengFaFactory chengFaFactory = new ChengFaFactory();
Operation operation1 = chengFaFactory.createOperation();
operation1.setNum2(10);
operation1.setNum1(20);
System.out.println(operation1.getResult());
interface Computer {}
class Macbook implements Computer {}
class Surface implements Computer {}
class Factory {
public Computer produceComputer(String type) {
Computer c = null;
if(type.equals("macbook")){
c = new Macbook();
}else if(type.equals("surface")){
c = new Surface();
}
return c;
}
}
class A{
public int func1(int a, int b)
{return a-b;}
}
public class Client{
public static void main(String[] args){
A a = new A();
System.out.println("100-50="+a.func1(100, 50));
System.out.println("100-80="+a.func1(100, 80));
}
}
运行结果:
100-50=50
100-80=20
class B extends A{
public int func1(int a, int b){
return a+b;
}
public int func2(int a, int b){
return func1(a,b)+100;
}
}
public class Client{
public static void main(String[] args){
B b = new B();
System.out.println("100-50="+b.func1(100, 50));
System.out.println("100-80="+b.func1(100, 80));
System.out.println("100+20+100="+b.func2(100, 20));}
}
8.3.4、依赖倒转原则(DIP)
开闭原则的基础,具体内容:针对接口编程,不要对实现编程;
高层模块不应该依赖低层模块。两个都应该依赖抽象。
抽象不应该依赖细节。细节应该依赖抽象。
例子:以顾客购物场景为例,假设今天,顾客想去万达买点东西,就有了下面代码
class Customer {
public void shopping(WanDaShop shop) {
//购物
System.out.println(shop.sell());
}
}
第二天,顾客觉得万达东西太贵了,想换一家店购买,比如永辉超市,于是又修改代码为:
class Customer {
public void shopping(YonghuiShop shop) {
//购物
System.out.println(shop.sell());
}
}
public class Person {
public static final Person person = new Person();
//构造方法私有化
private Person(){}
public static Person getInstance(){
return person;
}
}
public class Test {
public static void main(String[] args) {
//Person person = new Person();
//Person person1 = new Person();
//System.out.println(person == person1);
Person p1 = Person.getInstance();
Person p2 = Person.getInstance();
System.out.println(p1 == p2);
}
}
public class Student implements Cloneable {
@Override
protected void finalize() throws Throwable {
System.out.println("对象被回收了,finalize()方法自动被调用了!");
}
}
public class TestStudent {
public static void main(String[] args) throws CloneNotSupportedException {
Student s1 = new Student();
new Student();
new Student();
new Student();
System.gc();
}
}
public class Demo01 {
public static void main(String[] args) {
Integer i1 = new Integer(123);
//1,XXXValue:将包装类转为基本类型
int i2 = i1.intValue();
//2,toString() 将包装类以字符串的形式返回
String i3 = i1.toString();
//3,valueOf() 包装类都有一个valueOf方法
//通过类名直接调用,传入字符串或者基本类型,返回包装类型
//注意,传入字符串的时候,不能随便传,要符合对应的类型
Integer i4 = Integer.valueOf("100");
//4,parseXXX : 将字符串转换为对应包装类的基本数据类型
int i5 = Integer.parseInt("100");
Float f1 = new Float(3.3);
//1,XXXValue:将包装类转为基本类型
float f2 = f1.floatValue();
Boolean b1 = new Boolean(true);
//1,XXXValue:将包装类转为基本类型
boolean b2 = b1.booleanValue();
Character c1 = new Character('A');
//1,XXXValue:将包装类转为基本类型
char c2 = c1.charValue();
//Character类的valueof没有字符串类型的参数
Character.valueOf('a');
}
}
jdk1.5新特性 : 自动装箱和自动拆箱
//创建包装类对象
//Integer i = new Integer(100);
//自动装箱,将基本类型的值,直接赋值给对应的包装类对象
//系统其实省略一个步骤:
//Integer.valueOf(100);
Integer i = 100;
Character c = 'a';
//自动拆箱,将包装类型的对象,直接赋值给对应基本类型变量
//中间省略调用intValue()方法这个步骤
//int i1 = i.intValue();
int a = i; //直接把包装类对象,赋值给基本类型的变量
int nextInt(int bound) 返回伪随机的,均匀分布 int值介于0(含)和指定值(不包括),从该随机数生成器的序列绘制。
protected int next(int bits) 生成下一个伪随机数。
long nextLong() 返回下一个伪,均匀分布 long从这个随机数生成器的序列值
//Random类
public class Demo07 {
public static void main(String[] args) {
//无参构造的random对象
Random random = new Random();
int i = random.nextInt();
System.out.println(i);
int i1 = random.nextInt(100);
System.out.println(i1);
Random random1 = new Random(2000);
int i2 = random1.nextInt();
System.out.println(i2);
int i3 = random1.nextInt(100);
System.out.println(i3);
}
}
练习:
//写一个猜数字的小游戏
//提示用户,1-100随机数已经生成,让用户输入数值猜生成随机数大小
//如果猜小了,返回你猜小了
//猜大了,返回你猜大了
//猜中了,返回你猜对了,太棒了
//超过10次为猜中,游戏技术,并返回你太菜了,10次都没猜中!告诉他正确答案
9.6.3 BigInteger
大整数的运算
/*
BigInteger类
*/
public class Demo08 {
public static void main(String[] args) {
//Integer i = 1234567;
//i = i * 54321;
//System.out.println(i);
//System.out.println(Integer.MAX_VALUE);
Integer i1 = new Integer("2147483647");
System.out.println(i1);
//Integer i2 = new Integer("2147483648");
//System.out.println(i2);
BigInteger bi = new BigInteger("2147483648");
System.out.println(bi);
//System.out.println(bi + 100); //不能直接使用加号
BigInteger bi2 = new BigInteger("100");
//BigInteger add(BigInteger val)
//返回值为 (this + val)
System.out.println(bi.add(bi2));
//BigInteger divide(BigInteger val)
//返回值为 (this / val) 。
System.out.println(bi.divide(bi2));
//BigInteger multiply(BigInteger val)
//返回值为 (this * val) 。
System.out.println(bi.multiply(bi2));
//BigInteger subtract(BigInteger val)
//返回值为 (this - val) 。
System.out.println(bi.subtract(bi2));
//int intValue()
//将此BigInteger转换为 int
//如果bigInteger超过了范围,转为int之后,值会发生改变
int i = bi.intValue();
System.out.println(i);
}
}
public class StringBufferDemo01 {
public static void main(String[] args) {
//给String 拼接 10000次字符串
long start = System.currentTimeMillis();
String s = "hello";
for (int i = 0; i < 10000; i++) {
s += i;
}
long end = System.currentTimeMillis();
System.out.println(end - start);
//给StringBuffer拼接10000次字符串
long start1 = System.currentTimeMillis();
StringBuffer sb1 = new StringBuffer("hello");
for (int i = 0; i < 100000; i++) {
sb1.append(i);
}
long end1 = System.currentTimeMillis();
System.out.println(end1 - start1);
long start2 = System.currentTimeMillis();
StringBuilder sb2 = new StringBuilder("hello");
for (int i = 0; i < 100000; i++) {
sb2.append(i);
}
long end2 = System.currentTimeMillis();
System.out.println(end2 - start2);
}
}
public class StringBufferDemo02 {
public static void main(String[] args) {
//string ->stringbuffer
String s = "hello";
//直接赋值,强制转换都不行
//StringBuffer sb1 = (StringBuffer) s;
//1,通过构造方法
StringBuffer sb1 = new StringBuffer(s);
//2,通过append方法
StringBuffer sb2 = new StringBuffer();
sb2.append(s);
//StringBuffer -> String
//1,通过String类的构造方法
String s1 = new String(sb1);
//2,通过toStrig()方法
String s2 = sb1.toString();
}
}
让用户输入一段字符串,判断字符串是否是对称字符串,比如 aba ,abcdcba 就是对称字符串
9.6.7 Date类
Date类分为两个包,一个是sql包下的Date,一个是util包下的Date
sql包下的Date一般表示毫秒值,用来连接jdbc的时候,可以直接以字符串形式获取数据库中的时间
util包下的Date,一般用来表示生活中的时间格式,目前学习这个Date
构造方法
Date()
分配一个 Date对象,并初始化它,以当前时间创建一个Date对象
Date(long date)
分配一个 Date对象,传入一个毫秒值,根据毫秒值来创建Date对象
//创建日期类型 :
//1,无参构造
Date date = new Date();
System.out.println(date);
//2,使用毫秒值
long time = System.currentTimeMillis();
Date date1 = new Date(time);
System.out.println(date1);
public class DemoFormat {
public static void main(String[] args) throws ParseException {
//通过SimpleDateFormat完成Date和String之间的转换
//Date->String
//创建当前的时间对象
Date date = new Date();
//创建日期格式化对象
SimpleDateFormat sdf =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//调用方法
String stringTime = sdf.format(date);
System.out.println(stringTime);
//String-> Date
//声明一个字符串时间格式
String time = "2022-07-22 10:10:10";
Date date1 = sdf.parse(time);
System.out.println(date1);
}
}
计算出生天数
//让用户输入自己的生日,然后看看自己已经出生多少天了
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你的生日,参考格式:1999-11-11");
//接受生日输入
String birthday = scanner.next();
//生日转为Date,然后获取时间戳(毫秒值)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(birthday);
long time = date.getTime(); //获取毫秒值
long timeNow = System.currentTimeMillis();
//计算天数
long day = (timeNow - time) /1000/60/60/24;
System.out.println("天数" + day);
日期转换工具类
//日期工具类
public class DateUtil {
//日期转字符串方法
// 返回值 :String
//参数 :日期,格式
public static String dateToString(Date date,String pattern){
return new SimpleDateFormat(pattern).format(date);
}
//字符串转日期方法
// 返回值 :Date
//参数 :String日期,格式
public static Date stringToDate(String date,String pattern) throws ParseException {
return new SimpleDateFormat(pattern).parse(date);
}
}
public class CalendarDemo02 {
public static void main(String[] args) throws ParseException {
//利用日历类,完成时间的获取
//在计费系统中,需要计算两个时间的时间差,比如停车时间
// 从 7:30 进入停车场, 8:35分离场,每15分钟收费1块钱
//计算我需要交费多少钱
// 字符串时间对应的Date对象
String time1 = "07:30";
String time2 = "08:35";
Date startDate = DateUtil.stringToDate(time1, "HH:mm");
Date endDate = DateUtil.stringToDate(time2, "HH:mm");
//设置日历类的时间
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
// 通过日历类分别获取到 开始时间的小时和分钟
c1.setTime(startDate);
int startHour = c1.get(Calendar.HOUR);
int startMinute = c1.get(Calendar.MINUTE);
//获取结束时间的小时和分钟
c2.setTime(endDate);
int endHour = c2.get(Calendar.HOUR);
int endMinute = c2.get(Calendar.MINUTE);
//计算总时间,计算价格
int money = ((endHour * 60 + endMinute) - (startHour * 60 + startMinute))/15 * 1;
System.out.println(money);
}
}
9.6.10 正则表达式
指的是符合一定规则的字符串,用来约束某些信息,在编写的时候,遵守指定的规则
正则的编写规范 :
1,字符格式
a 表示 匹配 a
[abc] 表示匹配 abc ,1次
[^abc] 表示除abc以外的 ,1次
[A-Z] 表示匹配大写字母 1次
[0-9] 表示匹配任意数字1次
[a-z] 表示匹配小写字母1次
[a-zA-Z0-9] 表示匹配大小写字母数字1次
2,次数格式
{n} 匹配指定的n次
{n,m} 匹配n到m次
{n,} 匹配最少n次,最高不限次数
? 一次或者0次
*0次或者多次
+1次或者多次
3,通配符
\转义符 ,将有特殊含义的字符转义为本来的含义
^表示以指定的内容
$表示以指定的内容结尾
\w 表示任意字符 ,相当于 [a-z_A-Z0-9]
\d 表示任意数字 ,相当于[0-9]
public class RegexDemo {
public static void main(String[] args) {
//测试用户输入的手机号码是否符合规范
//声明一个手机号码的正则表达式
String regex = "^[1][3-9]\\d{9}";
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个手机号码:");
String phoneNum = sc.next();
//调用方法,传入正则规则,判断是否符合
boolean b = phoneNum.matches(regex);
if (b){
System.out.println("手机号符合规范");
}else {
System.out.println("手机号不符合规范");
}
}
}
public class RegexDemo02 {
public static void main(String[] args) {
//写一个邮箱的正则表达式 [email protected]
//String regex = "[0-9a-zA-Z]{3,16}@[0-9a-zA-Z]{2,10}(\\.[a-z]{2,3}){1,2}";
String regex = "\\w{3,16}@\\w{2,10}(\\.\\w{2,3}){1,2}";
Scanner sc = new Scanner(System.in);
System.out.println("输入邮箱:");
String s = sc.next();
boolean b = s.matches(regex);
if (b){
System.out.println("符合规范");
}else {
System.out.println("不符合规范");
}
}
}
10 吃鸡游戏
package com.iweb.airui369.test;
/*
类 玩家 Player,开局的时候,默认血量为100,没有枪
属性 昵称 name
血量 HP
枪 gun
行为 捡枪(枪)
装弹(弹夹,子弹)
上膛(弹夹)
开枪(玩家)
掉血(伤害值)
*/
public class Player {
private String name;
private int HP = 100;
private Gun gun;
public Player() {
}
public Player(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getHP() {
return HP;
}
public void setHP(int HP) {
this.HP = HP;
}
// 捡枪(枪)
// 装弹(弹夹,子弹)
// 上膛(弹夹)
// 开枪(玩家)
// 掉血(伤害值)
//捡枪
public void takeGun(Gun gun){
//如果玩家没有枪,给他一把枪
if (this.gun == null){
this.gun = gun;
System.out.println("玩家" + name + "拿到枪!");
}else {
System.out.println("玩家" + name + "已经有枪了!");
}
}
//上膛
public void loadClip(Clips clips){
//有枪才能上弹夹
if (this.gun != null){
//需要通过枪去调用方法
this.gun.loadClips(clips);
System.out.println("玩家" + name + "给枪装上了弹夹!");
}else {
System.out.println("玩家" + name + "还没有拿到枪!");
}
}
//开枪方法
public void shot(Player player){
//有枪才能开枪
if (gun != null){
//弹夹为空
if (gun.getClips() == null){
System.out.println("枪里没有装弹夹!请装弹夹!");
}else {
//弹夹有了,判断弹夹有没有子弹
if (gun.getClips().getNum() == 0){
System.out.println("弹夹中没有子弹!");
}else {
System.out.println("玩家" + name + "开枪打中了" + player.name);
this.gun.shot(player);
}
}
}else {
System.out.println("玩家" + name + "没有枪,不能开枪!");
}
}
public void bloodLoss(int damage) {
//看看当前血量还有多少,到0就死亡
if (this.HP == 0){
System.out.println("玩家" + name + "已死亡!");
}else {
this.HP -= damage; //掉血
System.out.println("玩家" + name + "受到" + damage +
"点伤害,剩余" + this.HP + "血量!");
}
}
}
package com.iweb.airui369.test;
/*
类 枪
属性
弹夹 clips
行为
装弹夹=Player上膛(弹夹)
开枪(玩家) ,如果开枪没打中的话,提示放了一个空枪
*/
public class Gun {
private Clips clips;
public Clips getClips() {
return clips;
}
//开枪
public void shot(Player player){
//如果弹夹不为空,才能开枪
if (clips != null){
//弹夹调用出弹方法
Bullet bullet = clips.popBullet();
//如果子弹不为null,子弹可以击中玩家
if (bullet != null){
bullet.hit(player);
}else {
System.out.println("放了个空枪!");
}
}else {
System.out.println("枪没有弹夹,请上弹夹!");
}
}
public void loadClips(Clips clips) {
this.clips = clips;
System.out.println("枪的弹夹装好了!");
}
}
package com.iweb.airui369.test;
/*
类 弹夹,弹夹默认只能装入30颗子弹
属性 子弹 bullet
行为 装弹(子弹)
出弹()
*/
public class Clips {
private Bullet[] bullets = new Bullet[30];
private int num = 0; //子弹数量
public int getNum() {
return num;
}
//装弹方法
public void putBullet(Bullet bullet){
//如果弹夹有空了,才可以装弹
if (bullets.length == num){
System.out.println("弹夹的子弹是满的,不需要装弹!");
}else {
//从剩下子弹数量的下一位开始装弹
bullets[num] = bullet;
num++;
System.out.println("弹夹已经装了" + num + "颗子弹!");
}
}
//出弹方法
public Bullet popBullet(){
if (num == 0){
System.out.println("弹夹中子弹打完了!");
return null;
}
//每调用一次方法,子弹数量--,其实就是将子弹从数组中拿出来
//子弹是先进后出的结构,所以每次拿的是上面的
Bullet bullet = bullets[num-1];
System.out.println("弹夹中还剩" + --num + "个子弹!");
return bullet;
}
}
package com.iweb.airui369.test;
/*
类 子弹 默认伤害是10,命中玩家后玩家掉血
属性
伤害值 damage
行为
命中 hit(玩家)
*/
public class Bullet {
private int damage = 10; //默认值为10
public void hit(Player player){
player.bloodLoss(damage);
}
}
package com.iweb.airui369.test;
public class Test {
//设计一个吃鸡的游戏
// 类创建好以后,创建两个角色,角色A和角色B, 角色A出场后,拿到枪,
// 装上子弹以后,开枪打角色B,每次开枪需要返回 :
// A开枪打中了B,B的血量还有多少,如果没打中,就提示A放了一个空枪,没有打中B,直到B死亡,流程结束
public static void main(String[] args) {
Player a = new Player("A");
Player b = new Player("B");
//a.shot(b);
//a捡枪
Gun gun = new Gun(); //先创建枪
a.takeGun(gun);
//创建弹夹对象
Clips clips = new Clips();
a.loadClip(clips);
//装子弹
for (int i = 0; i < 30; i++) {
clips.putBullet(new Bullet());
}
//a.shot(b);
for (int i = 0; i < 20; i++) {
if (i % 2 == 0){
a.shot(b);
}else {
System.out.println("A放了空枪,没打中B~");
}
}
}
}
public class Demo01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入1-3之间的整数:");
int i = scanner.nextInt();
switch (i){
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
default:
System.out.println("输入错误");
break;
}
}
}
//自定义异常
public class GenderException extends Exception {
//构造方法
public GenderException(String message) {
super(message);
}
}
public class Test {
//在方法上继续抛出异常
public static void main(String[] args) {
try {
Student s = new Student();
s.setName("张三");
s.setGender("妖");
System.out.println(s);
} catch (GenderException e) {
//e.printStackTrace();
System.err.println("性别输入错误");
}
}
}
12 泛型、集合
12.1 泛型
概念: 有的时候,在使用数据类型的时候,不能明确具体要用的是哪个类型,那么就可以使用泛型
将来泛型可以使用在类、方法、接口 、集合等地方,使用比较广泛
泛型的格式 :
<数据类型>
12.1.1 泛型的使用
泛型使用在方法上
public class Demo01 {
//声明一个泛型的方法
//返回值类型、参数列表
public void show(T t){
System.out.println(t);
}
}
public class Test {
public static void main(String[] args) {
Demo01 demo01 = new Demo01();
demo01.show("hello");
demo01.show(100);
demo01.show(true);
}
}
泛型使用在类上
//将泛型定义在类上
public class Demo02 {
private T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
public class Test1 {
public static void main(String[] args) {
//泛型类的测试
//new对象的时候可以不指定泛型
//不指定泛型,默认这个泛型就是Object
Demo02 demo02 = new Demo02();
demo02.setObj("hello");
String s = (String) demo02.getObj();
System.out.println(s);
demo02.setObj(new Integer(30));
Integer i = (Integer) demo02.getObj();
System.out.println(i);
//创建对象的时候,明确指定泛型的类型
Demo02 stringDemo02 = new Demo02<>();
stringDemo02.setObj("张三");
String s1 = stringDemo02.getObj();
System.out.println(s1);
//泛型指定了类型后,就不能使用其他类型了
//stringDemo02.setObj(30);
Demo02 integerDemo02 = new Demo02<>();
integerDemo02.setObj(50); // 直接传入数字,有自动装箱
Integer i1 = integerDemo02.getObj();
System.out.println(i1);
}
}
泛型定义在接口上
//在接口上使用泛型
public interface Demo03 {
void show(T t);
}
public class Demo04 implements Demo03 {
@Override
public void show(Object o) {
System.out.println(o);
}
}
public class Test2 {
public static void main(String[] args) {
Demo03 d1 = new Demo04();
d1.show("hello");
Demo03 d2 = new Demo04<>();
d2.show("hello");
//d2.show(30);
Demo03 d3 = new Demo04<>();
d3.show(30);
}
}
12.1.1 泛型通配符
> ?表示任意类型,没有明确的话,表示Object以及任意的Java类
super T> 向上限定,T及其父类
extends T> 向下限定,T及其子类
//泛型的通配符的使用
public class Demo05 {
public static void main(String[] args) {
//使用集合的声明
Collection> c1 = new ArrayList
public E next() {
checkForComodification();
int i = cursor;
Object[] elementData = ArrayList.this.elementData;
cursor = i + 1;
return (E) elementData[lastRet = i];
}
void linkLast(E e) {
//使用一个临时变量来记录操作前的last属性信息
final Node l = last;
//创建一个新的节点,item属性值为e,新节点的前置对象指向原来的尾节点,后置节点为null
final Node newNode = new Node<>(l, e, null);
//因为要在双向链表的尾节点添加新的节点,将last属性中的信息重新设置
last = newNode;
//条件成立,说明双向链表没有任何节点
if (l == null)
//将first节点指向新的节点,first和last都同时指向同一个节点
first = newNode;
else
//不成立,双向链表至少有一个节点,将原来的尾节点的后置节点指向新的尾节点
l.next = newNode;
//双向链表长度 + 1
size++;
//linkedList集合的操作次数 + 1
modCount++;
}
addFirst方法
public void addFirst(E e) {
linkFirst(e);
}
/**
* Links e as first element.
*/
private void linkFirst(E e) {
//使用一个临时的变量记录操作前first属性的信息
final Node f = first;
//创建一个数据信息为e的新节点,该节点前置节点引用为null,后置节点引用指向原先的头节点
final Node newNode = new Node<>(null, e, f);
//因为要在双向链表头部添加新的节点,将first属性中的信息重新设置
first = newNode;
//条件成立,说明双向链表没有任何节点
if (f == null)
//将last节点也指向新的节点,这样first和last节点属性同时指向同一个节点
last = newNode;
else
//不成立,说明双向链表至少有一个节点,只需要把原来的头节点的前置节点引用指向新的头节点
f.prev = newNode;
//双向链表长度 + 1
size++;
//linkedList集合的操作次数 + 1
modCount++;
}
remove方法
public boolean remove(Object o) {
if (o == null) {
for (Node x = first; x != null; x = x.next) {
if (x.item == null) {
unlink(x);
return true;
}
}
} else {
for (Node x = first; x != null; x = x.next) {
if (o.equals(x.item)) {
unlink(x);
return true;
}
}
}
return false;
}
实际调用的是unlink()方法
E unlink(Node x) {
// assert x != null;
//定义一个element变量,记录当前节点中的数据对象,以便方法最后返回
final E element = x.item;
//创建一个next节点,记录当前节点中的后置节点引用,可能为null
final Node next = x.next;
//创建一个prev节点,记录当前节点中的前置节点引用,可能为null
final Node prev = x.prev;
//如果条件成立,说明被移除的x节点是双向链表的头节点
if (prev == null) {
//将x的后置节点设置为新的头节点
first = next;
} else {
//将x的前置节点中的后置节点设置为移除的x节点的后置节点
prev.next = next;
//将移除的x节点的前置节点设置为null
x.prev = null;
}
//如果条件成立,说明被移除的x节点是双向链表的尾节点
if (next == null) {
//将移除的x的节点的前置节点设置为新的尾节点
last = prev;
} else {
//将x的后置节点中的前置节点设置为移除x节点的前置节点
next.prev = prev;
//将移除的x节点的后置节点设置为null
x.next = null;
}
//将移除的x节点中的数据对象设置为null
x.item = null;
//双向链表长度 - 1
size--;
//LinkedList集合操作次数 + 1
modCount++;
return element;
}
get方法
可以看到get方法实现就两段代码:
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
我们进去看一下具体的实现是怎么样的:
Node node(int index) {
// assert isElementIndex(index);
//下标长度小于一半,就从头遍历
if (index < (size >> 1)) {
Node x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
//否则就从尾部遍历
Node x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
set方法
set方法和get方法其实差不多,根据下标来判断是从头遍历还是从尾遍历
public E set(int index, E element) {
checkElementIndex(index);
Node x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
}
例如,你想myuser使用mypassword从任何主机连接到mysql服务器的话。
GRANT ALL PRIVILEGES ON *.* TO 'myuser'@'%'IDENTIFIED BY 'mypassword' WI
TH GRANT OPTION;
如果你想允许用户myuser从ip为192.168.1.6的主机连接到mysql服务器,并使用mypassword作
在 Service Pack 4 (SP 4), 是运行 Microsoft Windows Server 2003、 Microsoft Windows Storage Server 2003 或 Microsoft Windows 2000 服务器上您尝试安装 Microsoft SQL Server 2000 通过卷许可协议 (VLA) 媒体。 这样做, 收到以下错误信息CD KEY的 SQ
OS 7 has a new method that allows you to draw a view hierarchy into the current graphics context. This can be used to get an UIImage very fast.
I implemented a category method on UIView to get the vi
方法一:
在my.ini的[mysqld]字段加入:
skip-grant-tables
重启mysql服务,这时的mysql不需要密码即可登录数据库
然后进入mysql
mysql>use mysql;
mysql>更新 user set password=password('新密码') WHERE User='root';
mysq
背景
2014年11月12日,ASP.NET之父、微软云计算与企业级产品工程部执行副总裁Scott Guthrie,在Connect全球开发者在线会议上宣布,微软将开源全部.NET核心运行时,并将.NET 扩展为可在 Linux 和 Mac OS 平台上运行。.NET核心运行时将基于MIT开源许可协议发布,其中将包括执行.NET代码所需的一切项目——CLR、JIT编译器、垃圾收集器(GC)和核心