javadoc -d 文件夹地址 javadoc标签 XXX.java
System.out.println(100+98); //198
System.out.println("100"+98); //10098
System.out.println(100+"Hello"); //100Hello
System.out.println("Hello"+100+98); //Hello10098
double a = 0.92381930109121314334452222222;
System.out.println(a); //0.9238193010912131
float b = 0.213123123123f;
System.out.println(b); //0.21312313
//一些小细节
double a = 2.7;
double b = 8.1 / 3; //实际结果为2.7
System.out.println(a); //2.7
System.out.println(b); //2.6999999999999997
if(a == b){
System.out.println("相等");
}else{
System.out.println("不相等"); //输出不相等
}
//由此我们可以得到一个重要结论
//当对两个运算结果为小数的进行判断比较是,应当小心
//应该用两个小数的差值的绝对值小于某个很小的范围时,认为两个运算结果相等
//应按照如下写法
if(Math.abs(a - b) < 0.0001){
System.out.println("相等"); //输出相等
}
//细节
int n1 = 10;
float d1 = n1 + 1.1; //错误,右边其实结果是double类型
float d1 = n1 + 1.1F; //正确写法
System.out.println(d1);
int n2 = 1.0; //错误 右边是double 高精度不能自动转换为低精度
//byte和short、char之间不发生自动类型转换
//byte和int自动类型转换的一些小细节
byte b1 = 10; //可以,具体数复制给byte时,先判断数值范围,再判断类型 10在byte范围内:-128-127
int a = 1;
b1 = a; //变量a在内存中占四个字节,是不能把他赋给byte,因为byte只有一个字节的空间
char c1 = 'a';
b1 = c1; //错误,byte和char之间不能自动类型转换
//byte、short、char之间可以计算,在计算时首先转换为int类型
byte b2 = 1;
byte b3 = 1;
short s1 = 1;
short s2 = s1 + b2; // 错误,b2 + s1 在计算时转换为了int型
int b = s1 + b2; //正确
byte b4 = b2 + b3; //错误,b2 + b3 ==> int
//boolean 不参与类型的自动转换
//自动提升原则:表达式结果的类型自动提升为操作数中最大的类型
byte b5 = 1;
short s4 = 100;
int c = 1;
double num = 1.1;
float f1 = 1.1f;
double num1 = b5 + s4 + c + num; //必须用double类型的变量接收右边的运算结果,因为右边运算结果的类型以及提升到double类型
double num2 = b5 + s4 + c + f1; //这样可以,右边运算结果为float,满足自动转换原则
int a = (int)10+ 2.1*2; //错误,右边其实还是double型
//正确写法
int a = (int)(10+ 2.1*2);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-881UZUUn-1652873405290)(https://cdn.jsdelivr.net/gh/MCXXHYK/PicGo/202205121717674.png#crop=0&crop=0&crop=1&crop=1&id=HDf9U&originHeight=896&originWidth=1356&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)]
1.** 基本数据类型转字符串**:加 “”
int n1 = 100;
float f1 = 4.5F;
double d1 = 1.2;
boolean b1 = true;
String s1 = n1 + "";
String s2 = f1 + "";
String s3= d1 + "";
String s4 = b1 + "";
System.out.println(s1 + " " + s2 + " " + s3 + " " + s4); //100 4.5 1.2 true 字符串
**字符串转基本数据类型 **
int a =Integer.parseInt("123");
double b = Double.parseDouble("123");
float f = Float.parseFloat("123");
short s = Short.parseShort("12");
long l = Long.parseLong("2131");
boolean b = Boolean.parseBoolean("true");
byte by = Byte.parseByte("11");
//字符串==>取出字符
String s1 = "123";
char c1 = s1.charAt(0); //1
char c2 = s1.charAt(1); //2
char c3 = s1.charAt(2); //3
boolean judge = "hh" instanceof String; //true
tips:**复合赋值运算符再进行计算时会进行类型转换 **
byte b1 = 123;
b1 += 1; //等价于 b1 = (byte)(b1 + 1);
//分析:按理说 b1 += 1;右边是 b1 +1 ==>int 赋值给左边byte会发生错误,
//但是这里其实复合赋值运算符进行运算是会自动进行类型转换的
//b1++也是如此
//b1++等价于 b1 = (byte)(b1+1); 也会发生类型转换
//细节
int i = 1;
i = i++; //1) temp = i ; 2) i = i +1; 3) i = temp; 执行顺序是这样的
System.out.println(i); //1
int j = 0;
j = i++; //1) temp = i ; 2) i = i +1; 3) j = temp; 执行顺序是这样的 j=1
int a = 1;
a = ++a;
System.out.println(a); //2 执行顺序 1) a = a +1; 2) temp = a ; 3) a = temp;
import java.util.Scanner; //导包
public class UserScanner {
public static void main(String[] args){
//1.创建对象
Scanner sc = new Scanner(System.in);
//2.调用方法
String s1 = sc.next(); //字符串
int n1 = sc.nextInt(); //整型值
double d1 = sc.nextDouble();//浮点型输入
char c1 = sc.next().charAt(0); // 字符型输入
System.out.println("==================");
System.out.println(s1);
System.out.println(n1);
System.out.println(d1);
System.out.println(c1);
// System.out.println(s1);
}
}
/*
* 1层 4空格 1star
*** 2层 3空格 3star
***** 3层 2空格 5star
******* 4层 1空格 7star
********* 5层 0空格 9star
*/
/*
* 1层 4空格 1star
* * 2层 3空格 2star
* * 3层 2空格 2star
* * 4层 1空格 2star
********* 5层 0空格 9star
*/
public class Pyramid {
void disPlayPyramid () {
int totol = 5;
//i控制层数
for (int i = 1 ; i <= totol ; i++) {
//每次打印star之前先打印空格
for (int k = 1; k <= totol-i; k++){
System.out.print(" ");
}
//j控制每一层打印的star个数
for (int j = 1;j <= 2*i-1;j++){
if(j == 1 || j == 2*i-1 || i == totol){
System.out.print("*");
}else{
System.out.print(" ");
}
}
System.out.println("");
}
}
public static void main(String[] args) {
Pyramid py = new Pyramid();
py.disPlayPyramid();
}
}
//2 0010 3 0011 2 & 3 = 0010 ==> 2
//-2 原码:10000000 00000000 00000000 00000010
// 补码:11111111 11111111 11111111 11111110
// ~-2 00000000 00000000 00000000 00000001 这是补码,运算结果要转成原码
// 运算结果的原码:00000000 00000000 00000000 00000001
// ~-2 ==> 1
Double d1 = Math.random(); // 返回值时介于(0.00,1.00)的Double值
//随机生成1-100之间的随机整数
int n1 = (int)(Math.random()*100)+1 //(int)(Math.random()*100) 0-99
//实现登录验证,有三次机会,如果用户名为”胡永康“,密码为”123456“,则提示登录成功;
//否则提示登录失败,并显示还有几次机会
void loginValidate(){
int n = 3;
Scanner sc = new Scanner(System.in);
for( int i = 1; i <=n; i++){
System.out.print("请输入用户名:");
String uname = sc.next();
System.out.println("");
System.out.print("请输入密码:");
String password = sc.next();
if("胡永康".equals(uname) && "123456".equals(password)){
System.out.println("登录成功....");
break;
}else{
System.out.println("登录失败,还剩"+(n-i)+"次机会!");
}
}
}
//1.动态初始化
int[] a = new int[5]; //数组动态初始化
int a[] = new int[5]; //两种写法均可
//也可以先声明再初始化
int[] a; // 先只声明,而不分配空间
a = new int[5]; //此时分配空间
//2.静态初始化
int a[] = {2,5,6,2,5,7,9};
int \ byte \ short \ long ==> 0 float ==> 0.0 double ==> 0.0
char ==> /u0000 string ==> null boolean ==> false
//扩容arr数组
int[] arr = {1,2,3};
//1.创建新的数组
int[] arrNew = new int[arr.length + 1]; //给新的数组创建原来的数组长度加一的空间
//2.遍历将原来的数组内容依次拷贝过来
for( int i = 0; i < arr.length; i++){
arrNew[i] = arr[i];
}
//3.把新内容填入新的数组
arrNew[arr.length] = 4;
//4.让原来的数组名指向新的数组
arr = arrNew; //arrNew[]自动被销毁(垃圾回收机制)
import java.util.Scanner;
public class ArrayAdd {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//原来的数组
int[] arr = {1,2,3};
do {
//1.创建新数组
int arrNew[] = new int[arr.length+1];
//2.拷贝原来数组内容到新数组
for( int i = 0; i < arr.length; i++) {
arrNew[i] = arr[i];
}
//3.询问用户是否添加新内容到数组
System.out.println("是否添加新内容到数组?(Y/N)");
char input = sc.next().charAt(0);
if( input == 'N') {
break;
}else if ( input == 'Y') {
System.out.println("请输入你想添加的数值:");
//3.获取要添加的数值
Integer addNum = sc.nextInt();
arrNew[arr.length] = addNum;
//4.将原来的的数组名指向新的数组
arr = arrNew;
System.out.println("添加成功!===========");
//5.打印数组中当前数据
for ( int i = 0; i < arr.length; i++ ) {
System.out.print("arr["+i+"]==>"+arr[i]+"\t");
}
}else{
System.out.println("添加失败!");
break;
}
}while(true);
}
}
import java.util.Scanner;
public class ArrayReduce {
public static void main(String[] args) {
//1.定义一个数组
int[] arr = {1,2,3};
//2.创建输入环境
Scanner sc = new Scanner(System.in);
//3.进入数组缩减
do {
//4.定义一个新的数组
int[] arrNew = new int[arr.length - 1];
System.out.println("是否要缩减数组?(y/n)");
char input = sc.next().charAt(0);
if( input == 'n'){
break;
}else if ( input == 'y' && arr.length > 1) {
//5.拷贝前length-1个元素到新数组
for ( int i = 0; i < arrNew.length; i++) {
arrNew[i] = arr[i];
}
//6.原来数组指向新的数组
arr = arrNew;
//7.打印缩减后的数组
System.out.println("缩减后的数组==================");
for ( int j = 0; j < arr.length ; j++) {
System.out.print(arr[j]+"\t");
}
}else if ( arr.length <= 1 ){
System.out.println("不能再缩减了!");
break;
}
}while(true);
}
}
//将其:57,12,63,7,4,9,12,52使用冒泡排序按照从小到大的顺序排序
public class BubbleSort {
public static void main(String[] args){
//1.定义一个数组存放数据,静态初始化数组
int[] arr = {57,12,63,7,4,9,12,52};
//2.冒泡排序 arr.length -1 趟排序 每趟排序确定一个最大值 i ==> 趟数 ==> 已排好序的数个数
for (int i = 0 ; i < arr.length - 1 ; i++ ) {
int flag = 1;
if( arr.length == 0) {
System.out.println("排序失败,数组长度为0!");
break;
}
//3.一趟冒泡排序 只给前面未被排序的元素排序 后面 i 个元素已经排好序 <==> int j = 0; j < arr.length - 1 - i
for( int j = 0; j < arr.length - 1 - i; j++) {
//比较相邻元素大小,若不是按照递增顺序,则发生交换
if( arr[j] > arr[j + 1]){
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = -1;
}
}
//如果一趟排序之后flag没变化,说明数组已经有序,无需在进行下次排序,直接跳出循环
if(flag == 1){
break;
}else{
System.out.println("\n第"+(i+1)+"趟排序后的数组===========");
for ( int k = 0; k < arr.length; k++ ) {
System.out.print(arr[k]+"\t");
}
}
}
//4.打印排序后的数组
System.out.println("\n全部排序完成后的数组===========");
for ( int k = 0; k < arr.length; k++ ) {
System.out.print(arr[k]+"\t");
}
}
}
public static void main(String[] args){
int[][] arr = {{1, 2, 3, 4, 5}, {0, 0, 1, 2, 3}, {1, 2, 5, 3, 7}, {4, 5, 6, 2, 1}, {0, 0, 0, 0, 0}};
for( int i = 0; i< arr.length; i++){
for( int j = 0; j < arr[i].length; j++){
System.out.print(arr[i][j]+" ");
}
System.out.println("");
}
}
public static void main(String[] args){
// int[][] arr = new int[i][j]; i 代表这个数组初始化为含有 i 个一维数组的数组,j代表每个一维数组含有j个元素
int[][] arr = new int[5][4]; //5 代表这个数组初始化为含有5个一维数组的数组,4代表每个一维数组含有4个元素
}
/*
用二维数组打印以下:
1
2 2
3 3 3
*/
public static void main(String[] args){
// int[][] arr = new int[i][]; i 代表这个数组初始化为含有 i 个一维数组的数组,但是每个一维数组还没有开辟空间
int[][] arr = new int[3][]; //3 代表这个数组初始化为含有5个一维数组的数组,但是每个一维数组还没有开辟空间
for( int i = 0; i < arr.length; i++) {
//给二维数组中的每一个一维数组开辟内存空间;如果不给每个一维数组分配空间,那么每个一维数组都为 null,即arr[i] == null
arr[i] = new int[i + 1];
//给一维数组遍历赋值
for( int j = 0; j < arr[i].length; j++) {
arr[i][j] = i+1;
}
}
System.out.println("====arr元素=====");
for( int i = 0; i < arr.length; i++) {
for( int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j]+" ");
}
System.out.println("");
}
}
/*
使用一个二维数组打印杨辉三角形
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
每行首个元素和最后一个元素都是1
从第三行开始,除了第一个元素和最后一个元素,每个元素都是上一行同一列元素加上上一行前一列的和
即 arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1]
*/
public class YangHui {
public static void main(String[] args) {
//动态创建一个二维数组
int[][] arr = new int[10][];
//遍历二维数组
for( int i = 0; i < arr.length; i++) {
//给每一个一维数组开辟内存空间
arr[i] = new int[i + 1];
//遍历一维数组
for( int j = 0; j < arr[i].length; j++) {
if( j == 0 || j == arr[i].length - 1) {
arr[i][j] = 1;
}else{
arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
}
}
}
// 打印二维数组
for( int i = 0; i < arr.length; i++) {
for( int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j]+"\t");
}
System.out.println("");
}
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u1Hkpi4B-1652873405294)(https://raw.githubusercontent.com/MCXXHYK/PicGo/main/image-20220503200153147.png#crop=0&crop=0&crop=1&crop=1&id=EVclS&originHeight=1086&originWidth=2484&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pHktv11U-1652873405297)(https://raw.githubusercontent.com/MCXXHYK/PicGo/main/image-20220503200311717.png#crop=0&crop=0&crop=1&crop=1&id=QwwBU&originHeight=1058&originWidth=2458&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)]
//一个方法只能有一个返回值,如何返回多个返回值?可用数组解决
class AA {
public int[] getSumAndSub(int num1, int num2) {
int[] resArr = new int[2];
resArr[0] = num1 + num2;
resArr[1] = num1 - num2;
//用数组返回多个返回值
return resArr;
}
}
递归必须向退出递归的条件逼近,否则就会无限递归,造成栈溢出。
/*
迷宫问题求解:
让小球自己找到路径
用二维数组解决
【规定】:
设置 0 ==> 不是墙,可以走
设置 1 ==> 墙,不能走
设置 2 ==> 探路,插旗,表示可以走(是通路)
设置 3 ==> 表示能走,但是是死路
起点初始化为(1,1)
二维数组定义为6行7列
探测路径为:下 ==> 右 ==> 上 ==> 左
【分析】:当数组终点为 2 时,说明已经找到了一条通路
*/
public class MiGong {
//初始化一个二维数组
static int[][] initTwoDemensionArray( int i, int j) {
//1.开辟二维数组的内存空间
int[][] arr = new int[i][j];
//2.初始化数组
/*
1 1 1 1 1 1 1
1 0 0 0 0 0 1
1 0 0 0 0 0 1
1 1 1 0 0 0 1
1 0 0 0 0 0 1
1 1 1 1 1 1 1
*/
for( int k = 0; k < i; k++) {
for( int t = 0; t < j; t++) {
if(k > 0 && t >0 && k < i-1 && t < j-1) {
arr[k][t] = 0;
}else{
arr[k][t] = 1;
}
}
arr[3][1] = 1;
arr[3][2] = 1;
}
return arr;
}
//打印二维数组
static void printTwoDemensionArray(int[][] arr) {
for( int i = 0; i < arr.length; i++) {
for( int j = 0; j <arr[i].length; j++) {
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
//寻找路径 策略:下 ==> 右 ==> 上 ==> 左
boolean findWay(int[][] arr, int i, int j) {
//判断是否到达终点 避坑:这里到达终点条件不要写成 i == 4 && j == 5 ,因为这样写的话arr[4][5]就不会插旗
if( arr[4][5] == 2) {
return true;
}else {
//1.判断当前位置状态( 0, 1, 2, 3 )
// 0代表此位置可以走,但是没有插旗,将其划定为路径
if (arr[i][j] == 0) {
//插旗 假定可以周围可以走通
arr[i][j] = 2;
//探路 下 ==> 右 ==> 上 ==> 左
if (findWay(arr, i + 1, j)) { //向下走
return true;
} else if (findWay(arr, i, j + 1)) { //向右走
return true;
} else if (findWay(arr, i - 1, j)) { //向上走
return true;
} else if (findWay(arr, i, j - 1)) { //向左走
return true;
} else {
arr[i][j] = 3;
return false;
}
} else { //当前位置为 1 / 2 / 3
return false;
}
}
}
public static void main(String[] args) {
//1.初始化迷宫
int[][] arr = initTwoDemensionArray(6,7);
//2.打印迷宫
printTwoDemensionArray(arr);
//3.从(1,1)出发找寻路径,终点为(4,5)
MiGong m1 = new MiGong();
m1.findWay(arr, 1, 1);
//4.打印插好旗的迷宫 (迷宫路径)
System.out.println("\n====迷宫路径=====\n");
m1.printTwoDemensionArray(arr);
}
/*
汉诺塔问题
*/
public class HanoiTower {
public static void main(String[] args) {
T t = new T();
// System.out.println("=========一个盘子============");
// t.move(1, 'A', 'B', 'C');
// System.out.println("=========两个盘子============");
// t.move(2, 'A', 'B', 'C');
// System.out.println("=========三个盘子============");
// t.move(3, 'A', 'B', 'C');
System.out.println("=========5个盘子============");
t.move(5, 'A', 'B', 'C');
}
}
class T {
int count = 1; //记录移动次数
//汉诺塔移动 num ==> 盘子数 source ==> 从哪里移动 via ==> 经过 distinct ==> 到哪里
public void move(int num, char source, char via, char distinct) {
//如果塔上只有一个盘子,直接把盘子 source -> distinct
if(num == 1) {
System.out.println("从"+source+"->"+distinct+"\t"+(count++));
}else{ //塔上有多个盘子 看出两个盘子
move(num - 1 , source, distinct, via); //把source上面的 num - 1 个盘子先通过 distinct 移动到 via
System.out.println("从"+source+"->"+distinct+"\t"+(count++)); // 最后一个盘子直接 source -> distinct
move(num - 1, via, source, distinct); //把via上面的 num - 1 个盘子先通过 source 移动到 distinct
}
}
}
/*
八皇后问题
*/
public int sum(int n1, int n2) {
return n1 + n2;
}
public void sum(int n1, int n2) {
int res = n1 + n2;
}
//上面两个方法重复定义,并不没有构成方法重载
class HspMethod {
//形参列表: 数据类型 + 三个点 + 参数名 nums可以当作数组来使用
public int sum(int... nums) {
int sum = 0;
System.out.println("接收了"+nums.length+"个参数");
for( int i = 0; i < nums.length; i++) {
return sum += nums[i];
}
}
}
用来创建对象时,就对对象进行初始化。
/*
[修饰符] 方法名 (形参列表){
方法体;
}
*/
/*
构造器
*/
public class Constructor01 {
public static void main(String[] args) {
Person p = new Person(18, "hyk");
System.out.println("名字:"+p.name+"\t"+"年龄:"+p.age);
}
}
class Person {
int age;
String name;
public Person(int pAge, String pName){
age = pAge;
name = pName;
}
}
//看一个案例
class Person{//类Person
int age=90;
String name;
Person(String n,int a){//构造器
name=n;//给属性赋值
age=a;
}
}
public class Constructor {
Person p=new Person("小倩",20);
}
/*
流程分析(面试题)
1.方法区中加载Person类信息(Person.class),只会加载一次
2.在堆中分配对象内存空间(地址)
3.完成对象初始化
3.1 默认初始化 age=0 name=null
3.2 显式初始化 age=90,name=null,
3.3 构造器的初始化 age =20, name=小倩
4.把对象在堆中的地址,返回给 p(p是对象名,也可以理解成是对象的引用)
*/
public Dog(String name, int age){//构造器
//this.name 就是当前对象的属性name
this.name = name:
//this.age 就是当前对象的属性age
this.age = age;
}
//哪个对象调用这个构造器,这个this就指的是哪个对象
public T() { // 无参构造
this("yk", 18); //在构造器中访问另外一个构造器 且此语句需放置构造器的第一条
}
public T(String name, int age) { // 无参构造
System.out.println("有参构造");
}
/*
比较两个人是否是同一个人:年龄和姓名都相同就认为是同一个人
*/
public class ThisExercise {
public static void main(String[] args) {
Person p1 = new Person(12,"张三");
Person p2 = new Person(12,"张三");
boolean res = p1.compareTo(p2);
System.out.println(res); //true
}
}
class Person {
//属性
int age;
String name;
//有参构造
public Person(int age, String name) {
this.name = name;
this.age = age;
}
//比较方法
public boolean compareTo(Person p) {
return this.name.equals(p.name) && this.age == p.age;
}
}
**包基本语法**
package com.hspedu; 需放在每个.java文件第一行
说明:
1. package 关键字,表示打包。
2. com.hspedu:表示包名
java提供四种访问控制修饰符号,用于**控制方法和属性(成员变量)**的访问权限(范围):
public void setXxx(类型 参数名){ //Xxx 表示某个属性
//加入数据验证的业务逻辑
属性=参数名;
}
public 数据类型 getXxx(){ //权限判断,Xxx 某个属性
return xx;
}
/*
看一个案例
那么在java中如何实现这种类似的控制呢?
请大家看一个小程序(EncapsulationO1java),
不能随便查看人的年龄,工资等隐私,
井对设置的年龄进行合理的验证,
年龄合理就设置:否则给默认,年龄,必须在1-120,
年龄,工资不能直接查看,name的长度在2-6字符之间
*/
PS:有参构造器可以和set方法一起使用,用来控制权限
继承可以解决代码复用,让我们的编程更加靠近人类思维,当多个类存在相同的属性(变量)和方法时,可以以这些类中抽象出父类,在父类中定义这些相同的属佳和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来声明继承父类即可。
class 子类 extends 父类{
}
//1)子类就会自动拥有父类定义的属性和方法
//2)父类又叫超类,基类.
//3)子类又叫派生类.
#【解读】:
#1.父类中有无参构造器时,子类中不管是有参构造器还是无参构造器都会隐藏一个super() ,默认调用父类的无参构造器。
#2.父类中没有无参构造器时,
# 即父类中有参构造器将默认无参构造器覆盖掉时,
# 且没有在父类中另外重新声明无参构造器,
# 则在子类的构造器中必须用super去指定使用父类的哪个构造器
# 完成对父类的初始化,否则编译无法通过。
#【另注】:初始化子类时,父类也会被初始化,且父类先被初始化
package com.test.extend_;
public class extend_test {
public static void main(String[] args) {
Son son = new Son();
System.out.println(son.name); //小头儿子
System.out.println(son.age); //30
System.out.println(son.hobby); //旅游
}
}
class GrandPa {
String name = "超大头爷爷";
String hobby = "旅游";
}
class Father extends GrandPa {
String name = "大头爸爸";
int age = 30;
}
class Son extends Father {
String name = "小头儿子";
}
/*
【运行原理】:
Son son = new Son();
1.先在方法区中加载类的信息,先加载最顶级父类的信息,再从上至下一直加载到子类
2.然后再在堆中,创建对象,对象中依次创建父类的属性,再创建子类的属性,字符串常量等引用类型
放在方法区的常量池,堆中会有一个地址指向它。所有的属性(从父类到子类)全部创建完毕,
一个子类对象在堆中就创建完成了,这时会在栈中创建一个引用指向堆中的对象。
*/
//如果这里属性如果被私有化了,别的类的不能访问,则子类可以通过父类提供的公共get/set方法访问该属性。
/*
class Father extends GrandPa {
String name = "大头爸爸";
private int age = 30;
public int getAge() {
return age;
}
}
public class extend_test {
public static void main(String[] args) {
Son son = new Son();
System.out.println(son.getAge());
}
}
/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GpD70MnO-1652873405299)(https://raw.githubusercontent.com/MCXXHYK/PicGo/main/image-20220505213741744.png#crop=0&crop=0&crop=1&crop=1&id=hHnyi&originHeight=814&originWidth=1814&originalType=binary&ratio=1&rotation=0&showTitle=false&status=done&style=none&title=)]
简单的说:方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型(或者返回类型也有继承关系)、参数一样,那么我们就说子类的这个方法覆盖了父类的方法
方法和对象具有多种形态,多态建立在继承和封装之上。
//案例
Animal animal = new Dog(); 【animal 编译类型是Animal,运行类型Dog】 父类引用可以指向子类对象(向上转型)
animal = new Cat(): 【animal 的运行类型变成了 Cat, 编译类型仍然是 Animal】
//案例
Animal animal = new Dog(); 【animal 编译类型是Animal,运行类型Dog】 父类引用可以指向子类对象(向上转型)
animal = new Cat(): 【animal 的运行类型变成了 Cat, 编译类型仍然是 Animal】
Animal animal = new Dog();
Dog dog = (Dog)animal; // 子类类型 引用名=(子类类型)父类引用
- **只能强转父类的引用,不能强转父类的对象**
- 要求**父类的引用必须指向的是当前目标类型的对象**
- **向下转型后,可以调用子类类型中所有的成员**,**解决了向上转型中父类引用不能调用子类特有成员的问题**
public class PolyDetail {
public static void main(String[] args) {
Base base = new Sub();
System.out.println(base.count); //看编译类型 10 属性没有重写之说,属性的值是由编译类型决定的,不能按照方法重写思路
base.ok(); //haha
}
}
class Base {
int count = 10;
public void ok() {
System.out.println("ok");
}
}
class Sub extends Base {
int count = 20;
@Override
public void ok() {
System.out.println("haha");
}
}
public class PolyDetail {
public static void main(String[] args) {
Base base = new Sub();
Sub sub = (Sub) base;
System.out.println(sub instanceof Sub); //true 对象 sub 的运行类型是否为 Sub 类型
System.out.println(sub instanceof Base); //true 对象 sub 的运行类型是否为 Base 类型的子类型
}
}
class Base {
}
class Sub extends Base {
}
public class Dynamic_Bind {
public static void main(String[] args) {
// a 编译类型 A 运行类型 B
A a = new B();
/**
* 把B中sum()注释后 40 -> 30
* 因为此时a.sum()调用的是父类的sum(),
* 父类sum()中有个getI(),
* 这个getI()调用的是子类的getI(),因为调用方法时,
* 该方法会和对象的运行类型绑定,即动态绑定机制,所以此处是 20 + 10 -> 30
*/
System.out.println(a.sum()); //40 -> 30
/**
* 把B中sum1()注释后 30 -> 20
* 因为此时a.sum1()调用的是父类的sum1(),
* 父类sum1()中直接return i + 10;
* 这个 i 调用的是父类的 i ,因为调用对象属性时,
* 该属性没有动态绑定机制,哪里声明 哪里使用, 所以此处是 10 + 10 -> 20
*/
System.out.println(a.sum1()); //30 -> 20
}
}
class A { //父类
public int i = 10;
public int sum() {
return getI() + 10;
}
public int sum1() {
return i + 10;
}
public int getI() {
return i;
}
}
class B extends A {//子类
public int i = 20;
// public int sum() {
// return i + 20;
// }
public int getI() {
return i;
}
// public int sum1() {
// return i + 10;
// }
}
package com.poly.polyArray;
/*
* 应用实例:现有一个继承结构如下:
* 要求创建1个Person对象、2个Student 对象和2个
Teacher对象,统一放在数组中,并调用每个对象say方法.
com.poly.polyArray.Person
name: String
age: int
say(): String
属性private
应用实例升级:如何调用子类特有的方法,比如
Teacher 有一个teach(), Student 有一个study()怎么调用?
**/
public class Poly_Array {
public static void main(String[] args) {
Person[] person = new Person[5];
person[0] = new Person("yk", 18);
person[1] = new Student("小明", 8, 59.5);
person[2] = new Student("小刚", 9, 99.5);
person[3] = new Teacher("smith", 30, 10000);
person[4] = new Teacher("武忠祥",60,200000);
for (int i = 0; i < person.length ; i++) {
//如果数组中元素不是Student类或者其子类
if( person[i] instanceof Student) {
Student stu = (Student) person[i];
stu.study();
//等价于
//((Student) person[i]).study();
}else if (person[i] instanceof Teacher) {
((Teacher) person[i]).teach();
}else if (person[i] instanceof Person) {
}else{
System.out.println("你的类型有误,请检查!");
}
// System.out.println(person[i].say());
}
}
}
package com.poly.equals;
public class Equals_Detail {
public static void main(String[] args) {
Equals_Test t1= new Equals_Test(18,"jack",20000);
Equals_Test t2= new Equals_Test(18,"jack",20000);
System.out.println(t1.equals(t2));;
}
}
package com.poly.equals;
public class Equals_Test {
private int age;
private String name;
private int id;
public Equals_Test(int age, String name, int id) {
this.age = age;
this.name = name;
this.id = id;
}
public boolean equals(Object o) {
if( o != null && o == this ) {
return true;
}else if(o instanceof Equals_Test) {
Equals_Test e = (Equals_Test) o;
return e.age == age && e.name.equals(name) && e.id == id;
}
return false;
}
}
/*名称 概念 用于基本数据类型 用于引用类型
== 比较运算符 可以,判断值是否相等 可以,判断两个对象是否相等
equals Object类的方法 不可以 可以,默认是判断两个对象是否相等
Java类都可以使用equals 但是子类往往重写该方法,比较对象的
属性是否相等,比如(String,lnteger)
*/
/*
案例演示:Monster [name, job, sal]案例:ToString_java
当直接输出一个对象时,toString 方法会被默认的调用
*/
@Override
public String toString() {
return "Monster{" +
"name='" + name + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
'}';
}
实现基于文本界面的《房屋出租软件》。能够实现对房屋信息的添加、修改和删除(用数组实现),并能够打印房屋明细表。
类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的
对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改
的也是同一个变量。
【访问修饰符】 static 【数据类型】 变量名(推荐)
或者
static 【访问修饰符】【数据类型】 变量名
类名.变量名 (推荐)
或者
对象名.变量名
【访问修饰符】 static 【数据类型】 方法名 {}(推荐)
或者
static 【访问修饰符】【数据类型】 方法名 {}
类名.类方法名 (推荐)
或者
对象名.类方法名
【前提】:满足访问修饰符的访问权限
public static void main(String[] args) {
}
javac Hello.java
java Hello tom jack smith #这里tom jack smith 就是传入String数组的参数,执行命令时传入
[修饰符]{
代码
}
说明注意:
package com.ykstudy.code_block;
public class CodeBlock {
public static void main(String[] args) {
new BB();
/*执行顺序:
(1)AA的代码块
(2)AA的构造器被调用
(3)BB的代码块
(4)BB的构造器被调用
*/
}
}
class AA {
{
System.out.println("AA的代码块");
}
public AA() {
//(1)super()
//(2)本类的普通代码块
System.out.println("AA的构造器被调用");
}
}
class BB extends AA {
{
System.out.println("BB的代码块");
}
public BB() {
//(1)super()
//(2)本类的普通代码块
System.out.println("BB的构造器被调用");
}
}
class A02 { //父类
private static int n1 = getVal01();
static {
System.out.println("A02的一个静态代码块..");//(2)
}
{
System.out.println("A02的第一个普通代码块..");//(5)
}
public int n3 = getVal02();//普通属性的初始化
public static int getVal01() {
System.out.println("getVal01");//(1)
return 10;
}
public int getVal02() {
System.out.println("getVal02");//(6)
return 10;
}
public A02() {//构造器
//隐藏
//super()
//普通代码和普通属性的初始化......
System.out.println("A02的构造器");//(7)
}
}
class B02 extends A02 { //
private static int n3 = getVal03();
static {
System.out.println("B02的一个静态代码块..");//(4)
}
public int n5 = getVal04();
{
System.out.println("B02的第一个普通代码块..");//(9)
}
public static int getVal03() {
System.out.println("getVal03");//(3)
return 10;
}
public int getVal04() {
System.out.println("getVal04");//(8)
return 10;
}
//一定要慢慢的去品..
public B02() {//构造器
//隐藏了
//super()
//普通代码块和普通属性的初始化...
System.out.println("B02的构造器");//(10)
}
}
public Class Code_Block_Detail {
public static void main(String[] args) {
new B02();//分析代码执行顺序
/*
(1)先进行类信息的加载,先加载父类信息(static修饰的属性和代码块),再加载子类信息(static修饰的属性和代码块)
(static修饰的方法只有在被调用时才会加载)
(2)类加载完毕之后,再进行对象创建
*/
}
}
package com.ykstudy.single_;
public class Single_ton01 {
public static void main(String[] args) {
//Girlfriend{name='小红'} 饿汉式
System.out.println(Girlfriend01.getInstance());
//Girlfriend02{name='美羊羊'} 懒汉式
System.out.println(Girlfriend02.getInstance());
}
}
//饿汉式
class Girlfriend01 {
private String name;
//2.在类的内部定义私有的静态变量保存新创建的对象
private static Girlfriend01 gf = new Girlfriend01("小红");
//1.构造器私有化
private Girlfriend01(String name) {
this.name = name;
}
//3.对外部提供一个公有的静态方法
public static Girlfriend01 getInstance() {
return gf;
}
@Override
public String toString() {
return "Girlfriend{" +
"name='" + name + '\'' +
'}';
}
}
//懒汉式
class Girlfriend02 {
private String name;
//2.定义一个私有静态变量(不初始化)保存类的对象
private static Girlfriend02 gf;
//1.构造器私有化
public Girlfriend02(String name) {
this.name = name;
}
//3.提供一个公共静态方法返回类的对象
public static Girlfriend02 getInstance() {
//4.判断类中保存对象的静态变量有没有被初始化
if(gf == null) {
gf = new Girlfriend02("美羊羊");
}
return gf;
}
@Override
public String toString() {
return "Girlfriend02{" +
"name='" + name + '\'' +
'}';
}
}
final 中文意思:最后的,最终的.
final 可以修饰类、属性、方法和局部变量.
在某些情况下,程序员可能有以下需求,就会使用到final:
class Demo{
public static final int i=16; //
static{
System.out.printiln(”韩顺平教育~");
}
当父类的一些方法不能确定时,可以用abstract关键字来修饰该方法,这个方法就是抽象方法,然后用abstract 来修饰该类就是抽象类。
//我们看看如何把Animal做成抽象类,并让子类Cat类实现。
abstract class Animal{
String name;
int age;
abstract public void cry(); //抽象方法没有方法体,写成抽象方法后,类也要加abstract修饰
}
public class Template_Mode {
public static void main(String[] args) {
B b = new B();
b.calculateTime();
}
}
/*
设计一个抽象类(Template),能完成如下功能:
编写方法calculateTime(),可以计算某段代码的耗时时间
编写抽象方法job()
*/
abstract class A {
//定义一个抽象方法,子类重写
public abstract void job();
//把抽象方法塞到这个普通方法里面形成模板
public void calculateTime() {
//开始时间
long start = System.currentTimeMillis();
//实现任务
job(); //动态绑定机制
//结束时间
long end = System.currentTimeMillis();
System.out.println("任务时间==" + (end - start)); //137
}
}
class B extends A {
@Override
public void job() {
long num = 0;
for (long i = 0; i < 100000000; i++) {
num *= i;
}
}
}
语法:
interface 接口名{
//属性
//方法(默认抽象方法;default修饰的方法;static修饰的方法)
int num;
//接口中方法默认为抽象方法
public void cry();
//jdk8以后接口中方法加关键词 static default修饰时方法可以有方法体
static void smile() {
System.out.println("haha");
}
default void play() {
System.out.println("playing now");
}
}
class 类名 implements 接口名{
/*
自己属性;
自己方法;
必须实现的接口的抽象方法
*/
}
小结:
接口不能被实例化
接口中所有的方法是 public方法,接口中抽象方法,可以不用abstract 修饰
void aa()
实际上是 public abstract void aa();
一个普通类实现接口,就必须将该接口的所有方法都实现。
抽象类实现接口,可以不用实现接口的方法。
一个类同时可以实现多个接口
接口中的属性,只能是final的,而且是 public static final 修饰符。比如:
int a=1;实际上是 public static final int a=1;(必须初始化)
接口中属性的访问形式:接口名.属性名
一个接口不能继承其它的类,但是可以继承多个别的接口
interface A extends B, C {
}
interface B {
}
interface C {
}
public class A {
public static void main(String[] args) {
//接口类型的变量可以指向实现了此接口的对象实例
IF if = new B();
}
}
Interface IF {
}
class B implements IF {
}
public class InterfacePolyPass {
public static void main(String[] args) {
//接口类型的变量可以指向,实现了该接口的类的对象实例
IG ig = new Teacher();
//如果IG 继承了 IH 接口,而Teacher 类实现了IG接口
//那么,实际上就相当于 Teacher 类也实现了IH接口
IH ih = new Teacher();
}
}
interface IH { }
interface IG extends IH{ }
class Teacher implements IG {
}
一个类的内部又完整的嵌套了另一个类结构,被嵌套的类称为内部类(inner class), 嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员.
class Outer{ //外部类
class Inner{ //内部类
}
class Other{ //外部其他类
}
【说明】:局部内部类是定义在外部类的局部位置,比如方法中,代码块中,并且有类名。
【演示】
//Outero2.this 本质就是外部类的对象,即哪个对象调用了m1, Outero2.this就是哪个对象
System.out printin("外部类的n2-”+外部类名.this.n2);
【说明】:匿名内部类是定义在外部类的局部位置,比如方法中,井且没有类名
(1) 本质是类;
** (2)内部类**
** (3)没有名字(系统底层分配名字)**
** (4)同时还是一个对象!!!**
new 类或接口(参数列表){
类体
};
【细节】:
【特点】:
// 使用匿名内部类优化(相当于创建了一个局部内部类)
Usb usb = new Usb(){ // Usb为一个接口
@Override
public void service(){
sout("连接电脑成功,fan开始工作")
}
};
usb.service();
public class AnoymousInnerClass {
public static void main(String[] args) {
Cellphone cellphone = new Cellphone();
/*
* Bell bell = new Bell() {
* @Override
* public void ring() {
* System.out.println("懒猪起床了!");
* }
* }
*
* 这里匿名内类系统底层给其分配了一个名字:AnoymousInnerClass$1
* 这里其实是
* class AnoymousInnerClass$1 implements Bell {
* @Override
* public void ring() {
* System.out.println("懒猪起床了!");
* System.out.println(this.getClass());
* }
* }
* */
cellphone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了!");
System.out.println(this.getClass()); //class AnoymousInnerClass$1
}
});
cellphone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴下课了!");
}
});
}
}
/*
有一个铃声接口Bell,里面有个ring方法。
有一个手机类Cellphone,具有闹钟功能 alarmClock, 参数是Bell类型(右图)
测试手机类的闹钟功能,通过匿名内部类(对象)作为参数,
打印:懒猪起床了再传入另一个匿名内部类(对象),打印:
小伙伴上课了
*/
interface Bell {
void ring();
}
class Cellphone {
public void alarmClock(Bell bell) {
bell.ring();
}
}
说明:成员内部类是定义在外部类的成员位置,并且没有static修饰。
class Outer01{ //外部类 private int n1 = 10;
public String name = "张三”;
class Innter01{
public void say(){
System.out.println("Outer01 的n1 =" + n1
+ "outer01 的 name "+ name );
}
}
}
比如前面案例,**在外部类的成员方法中创建成员内部类对象,再调用方法. **
//外部其他类访问成员内部类两种方式
//1.第一种方法 outter.new Inner() 相当于把new Inner() 当作outter的成员
Outter.Inner inner = outter.new Inner();
//2.在外部类中编写一个方法可以返回 Inner 对象
class Outer{ //外部类 private int n1 = 10;
public String name = "张三”;
class Innter{
public void say(){
System.out.println("Outer01 的n1 =" + n1
+ "outer01 的 name "+ name );
}
}
//第二种方式:在外部类中编写一个方法可以返回 Inner 对象
public Inner getInner() {
return new Inner();
}
}
public class Test {
public static void main(String[] args) {
Outter outter = new Outter();
//第一种方式
Outter.Inner inner = outter.new Inner();
}
}
【说明】:静态内部类是定义在外部类的成员位置,井且有static修饰
class Outer02{//外部类 private int n1 = 10;
private static String name = “张三”;
static class Inner02{
public void say(){
System.out.println(name);
//不能直接访问外部类的非静态成员
//System.out.println(n1);
}
}
public void show(){
//外部类使用内部类 new Inner020.say();
}
}
【说明】:
package com.yk.enum_;
/**
* @author YK
* @version 1.0
*/
public class Enumeration01 {
public static void main(String[] args) {
System.out.println(Season.SPRING);
}
}
class Season {
private String name;
private String weather;
//2.本类创建一组公开常量对象 3.对外暴露对象(通过对象添加 public static final 修饰符)
public static final Season SPRING = new Season("春天","温暖");
public static final Season SUMMER = new Season("夏天","炎热");
public static final Season AUTUMN = new Season("秋天","凉爽");
public static final Season WINTER = new Season("冬天","寒冷");
//1.构造器私有化
private Season(String name, String weather) {
this.weather = weather;
this.name = name;
}
//4.可以提供get()方法 但是不要提高set()方法
public String getName() {
return name;
}
public String getWeather() {
return weather;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", weather='" + weather + '\'' +
'}';
}
}
解读:常量名(实参列表)
package com.yk.enum_;
/**
* @author YK
* @version 1.0
*/
public class Enumeration01 {
public static void main(String[] args) {
System.out.println(Season.SPRING);
}
}
//1. class ==> enum
enum Season {
//2.public static final Season SPRING = new Season("春天","温暖")
//直接使用 SPRING("春天","温暖") 枚举常量对象写在最前面
SPRING("春天" ,"温暖") ,
SUMMER("夏天","炎热"),
AUTUMN("秋天","凉爽"),
WINTER("冬天","寒冷");
private String name;
private String weather;
//构造器私有化
private Season(String name, String weather) {
this.weather = weather;
this.name = name;
}
//可以提供get()方法 但是不要提高set()方法
public String getName() {
return name;
}
public String getWeather() {
return weather;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", weather='" + weather + '\'' +
'}';
}
}
/*
toString:Enum类己经重写过了,返回的是当前对象名,子类可以重写该方法,
用于返回对象的属性信息
name:返回当前对象名(常量名),子类中不能重写
ordinal:返回当前对象的位置号,默认从0开始
values:返回当前枚举类中所有的常量,返回的是 enum[] 类型
valueOf:将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常!
compareTo:比较两个枚举常量,比较的就是编号!返回的是编号差值
*/
package com.yk.enum_;
/**
* @author YK
* @version 1.0
* enum 常用方法
*/
public class Enumeration01 {
public static void main(String[] args) {
//toString: Season{name='春天', weather='温暖'}
System.out.println(Season.SPRING);
//values: 返回当前枚举类中所有的常量,返回的是 enum[] 类型
Season[] seasons = Season.values();
//增强for循环 从数组seasons中依次取出元素
for (Season season : seasons) {
System.out.println(season);
}
//name: 返回当前对象名(常量名),子类中不能重写
System.out.println(Season.SPRING.name()); //SPRING
//ordinal:返回当前对象的位置号,默认从0开始
System.out.println(Season.SPRING.ordinal()); // 0
//valueOf:将字符串转换成枚举对象,要求字符串必须为已有的常量名,否则报异常!
Season season1 = Season.valueOf("AUTUMN");
System.out.println(season1);
//compareTo:比较两个枚举常量,比较的就是编号!
System.out.println(Season.SPRING.compareTo(Season.SUMMER)); //-1
}
}
enum Season {
SPRING("春天" ,"温暖") ,
SUMMER("夏天","炎热"),
AUTUMN("秋天","凉爽"),
WINTER("冬天","寒冷");
private String name;
private String weather;
//构造器私有化
private Season(String name, String weather) {
this.weather = weather;
this.name = name;
}
//可以提供get()方法 但是不要提高set()方法
public String getName() {
return name;
}
public String getWeather() {
return weather;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", weather='" + weather + '\'' +
'}';
}
}
【说明】:
【说明】: