小黑子—Java从入门到入土过程:第六章
Java零基础入门6.0
- Java系列第六章
- 1. 面向对象综合练习
- 1.1 文字版格斗游戏=
- 参数占位,格式化输出回顾
- 关于printf和print和println的区别
- 1.2 对象数组练习
- 1.2.1 练习一
- 1.2.2 练习二
- 1.2.3 练习三
- 1.2.4 练习四
- 1.3 键盘录入回顾
- 1.4 复杂对象数组练习
- 1.4.1 复杂练习一
- 1.4.2 复杂练习二
- 2. API:应用程序编程接口
- 2.1 使用帮助文档
- 3. 字符串String
- 3.1 创建String对象的两种方式
- 3.2 字符串的比较
- 3.3 字符串练习
- 3.3.1 练习一:用户登录
- 3.3.2 练习二 ctrl+alt+v 自动生成左边赋值
- 3.3.3 练习三:字符串拼接和反转
- 3.3.4 练习四
- 3.3.5 练习五
- 3.4 StringBuilder
- 3.4.1 StringBuilder构造方法
- 3.4.2 StringBuilder常用方法
- 3.4.3 链式编程
- 3.4.4 StringJoiner
- 3.4.5 字符串原理
- 扩展底层原理1和2:字符串原理
- 扩展底层原理3:字符串拼接的底层原理
- 扩展底层原理5:StringBuilder提高效率原理
- 扩展底层原理5:StringBuilder源码分析
- ctrl + n IDEA快捷键 出现搜索界面
- 3.4.6 字符串综合练习
- 4. 集合
- 4.1 ArrayList 集合(之一)
- 4.2 集合综合练习
- 4.2.1 添加字符串和整数遍历
- 4.2.2 基本数据类型的包装类
- 4.2.3 添加学生对象并遍历
- 4.2.4 添加用户对象并判断是否存在
- 4.2.5 添加手机对象并返回要求的数据
- 5. 学生管理系统
- 5.1 学生管理系统升级版
- 6. 面向对象进阶
- 6.1 static
- 6.1.1 static-静态变量
- 6.1.2 static-静态方法和工具
- 静态方法
- 工具类
- 6.1.3 static-注意事项
- 6.1.4 重新认识main方法
- 6.2 继承
- 6.2.1 封装
- 6.2.2 继承的描述
- 6.2.3 继承的特点
- 6.2.4 子类继承父类的特性
- 6.2.5 终端的jps和jhsdb hsdb
- 6.2.6 继承中成员变量和成员方法的访问特点
- 继承成员变量
- 继承成员方法
- 6.2.6 继承中的构造方法
- 6.2.7 this、super关键字总结
- 6.3 认识多态
- 6.3.1 多态中调用成员的特点
- 6.3.2 多态的优势和弊端
- 6.3.3 instanceof 判断是不是相应类型
- 6.3.4 多态综合练习
- 6.4 包和 final
- 6.4.1 包
- 6.4.2 final (与static类似的关键字)
- 6.5 权限修饰符和代码块
- 6.5.1 权限修饰符
- 6.5.2 代码块
- 6.6 抽象类和抽象方法
- 6.7 接口
- 6.7.1 接口的细节:成员特点和各种接口的关系
- 6.7.2 接口和抽象类案例
- 6.7.3 接口的新增方法
- jdk8以后接口中新增的默认方法
- jdk8以后接口中新增的静态方法
- jdk9新增的私有方法
- 6.7.4 接口应用
- 6.7.5 适配器设计模型
- 6.8 初始内部类
- 6.8.1 成员内部类
- 6.8.2 静态内部类
- 6.8.3 局部内部类
- 6.8.4 匿名内部类
Java系列第六章
1. 面向对象综合练习
1.1 文字版格斗游戏=
1.简单版
User类包
package test3;import java.util.Random;public class User {private String name;private int blood;private char gender;private String face;//长相随机String[] boyfaces = {"风流俊雅", "气宇轩昂", "相貌英俊", "五官端正", "相貌平平", "一塌糊涂", "面目狰狞"};String[] girlfaces = {"美奂绝伦", "沉鱼落雁", "婷婷玉立", "身材娇好", "相貌平平", "相貌简陋", "惨不忍睹"};//attack攻击描述:String[] attacks_desc = {"%s使出了一招【背心钉】,转到对方的身后,一掌向%s背心的灵台穴拍去。","%s使出了一招【游空探爪】,飞起身形自半空中变掌为抓锁向%s。","%s大喝一声,身形下伏,一招【劈雷坠地】,捶向%s双腿。","%s运气于掌,一瞬间掌心变得血红,一式【掌心雷】,推向%s。","%s阴手翻起阳手跟进,一招【没逛拦】,结结实实的挺向%s。","%s上步抢身,招中套招,一招【劈挂连环】,连环攻向%s"};//injured受伤描述:String[] injureds_desc = {"结果%s退了半步,毫发无损","结果给%s造成一处瘀伤","结果一击命中,%s痛得弯下腰","结果%s痛苦地闷哼了一声,显然受了点内伤","结果%s摇摇晃晃,一跤摔倒在地","结果%s脸色一下变得惨白,连退了好几步","结果『轰』的一声,%s口中鲜血狂喷而出","结果%s一声惨叫,像滩软泥般塌了下去",};public User() {}public User(String name, int blood, char gengder) {this.name = name;this.blood = blood;this.gender = gender;//随机长相setFace(gender);}public char getGender() {return gender;}public void setGender(char gender) {this.gender = gender;}public String getFace() {return face;}public void setFace(char gender) {Random r = new Random();//长相随机if (gender == '男') {//从boyfaces里面随机长相int index = r.nextInt(boyfaces.length);this.face = boyfaces[index];} else if (gender == '女') {//从girlfaces里面随机长相int index = r.nextInt(girlfaces.length);this.face = girlfaces[index];} else {this.face = "面目狰狞";}}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getBlood() {return blood;}public void setBlood(int blood) {this.blood = blood;}//定义一个方法用于攻击别人//思考:谁攻击谁?//r1.攻击(r2)//方法的调用者去攻击参数public void attack(User user) {Random r = new Random();int index = r.nextInt(attacks_desc.length);String KungFu = attacks_desc[index];//输出一个攻击的效果System.out.printf(KungFu,this.getName(),user.getName());System.out.println();//计算造成的伤害int hurt = r.nextInt(20) + 1;//修改一下挨揍的人血量//剩余血量int remainBoold = user.getBlood() - hurt;//对剩余血量做一个验证,如果为负数了,就修改为0remainBoold = remainBoold < 0 ? 0 : remainBoold;//修改一下挨揍的人血量user.setBlood(remainBoold);//受伤的描述//血量>90 0 索引的描述//80 ~ 90 1索引的描述//70 ~ 80 2索引的描述// 60 ~ 70 3索引的描述// 40 ~ 60 4索引的描述// 20 ~ 40 5索引的描述// 10 ~ 20 6索引的描述// 小于10的 7索引的描述if(remainBoold > 90){System.out.printf(injureds_desc[0],user.getName());}else if(remainBoold>80&&remainBoold<=90){System.out.printf(injureds_desc[1],user.getName());}else if(remainBoold>70&&remainBoold<=80){System.out.printf(injureds_desc[2],user.getName());}else if(remainBoold>60&&remainBoold<=70){System.out.printf(injureds_desc[3],user.getName());}else if(remainBoold>40&&remainBoold<=60){System.out.printf(injureds_desc[4],user.getName());}else if(remainBoold>20&&remainBoold<=40){System.out.printf(injureds_desc[5],user.getName());}else if(remainBoold>10&&remainBoold<=200){System.out.printf(injureds_desc[6],user.getName());}else{System.out.printf(injureds_desc[7],user.getName());}System.out.println();}public void showRoleInfo() {System.out.println("姓名为" + getName());System.out.println("血量为" + getBlood());System.out.println("性别为" + getGender());System.out.println("长相为" + getFace());}
}
GameTest类包
package test3;public class GameTest {public static void main(String[] args) {// 1. 创建第一个角色User u1 = new User("麻瓜",100,'男');//2.创建第二个角色User u2 = new User("小老板",100,'男');//展示角色信息u1.showRoleInfo();System.out.println("------------------------");u2.showRoleInfo();System.out.println("------------------------");//3.开始格斗 回合制游戏while(true){//u1 开始攻击u2u1.attack(u1);//判断u2的剩余血量if(u2.getBlood()==0){System.out.println(u1.getName()+"K.O了"+u2.getName());break;}//u2开始攻击u1u2.attack(u1);if(u1.getBlood()==0){System.out.println(u2.getName()+"K.O了"+u1.getName());break;}}}
}
参数占位,格式化输出回顾
public static void main(String[] args) {//两部分参数://第一部分参数:要输出的内容%s(占位)// 第二部分参数:填充的数据System.out.printf("%s你好啊%s","张三","李四");//但是printf没有换行效果System.out.println();System.out.printf("你好啊%s","李四");}
关于printf和print和println的区别
- print为一般输出,同样不能保留精度格式转化,也不能换行输出
- printf常用于格式转换,但需要注意不是换行输出,只用于精度转换
- println为换行输出,不能用于格式转换
1.2 对象数组练习
1.2.1 练习一
Goods 类包
package test4;public class Goods {private String id;private String name;private double price;private int count;public Goods(){}public Goods(String id,String name,double price, int count){this.id = id;this.name = name;this.price = price;this.count = count;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}public int getCount() {return count;}public void setCount(int count) {this.count = count;}
}
GoodsTest 引入执行
package test4;public class GoodsTest {public static void main(String[] args) {//1.创建一个数组Goods[] arr = new Goods[3];//2.创建三个商品//快捷键 ctrl+p :把方法所对应的参数所展示Goods g1 = new Goods("001","华为p40",599.0,100);Goods g2 = new Goods("002","保温杯",297,50);Goods g3 = new Goods("003","洗衣机",10000,500);//3.把商品添加到数组中arr[0]=g1;arr[1]=g2;arr[2]=g3;//4.遍历for (int i = 0; i < arr.length; i++) {// i 索引 arr[i] 元素Goods goods = arr[i];System.out.println(goods.getId()+","+goods.getName()+","+goods.getPrice()+","+goods.getCount());}}
}
1.2.2 练习二
Car的javabeen包
package test5;public class Car {private String brand;//品牌private int price;//价格private String color;//颜色public Car(){}public Car(String brand, int price, String color) {this.brand = brand;this.price = price;this.color = color;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}
}
CarTest
package test5;import java.util.Scanner;public class CarTest {public static void main(String[] args) {//1.创建一个数组用来存3个汽车对象Car[] arr = new Car[3];//2.创建汽车对象,数据来自于键盘录入//如果把Car c = new Car();放在循环的外面,那么对象就只有一辆车//此时下面循环就对同一辆车的属性进行修改,而不是创建新的属性//所以此创建对象的代码不能写在循环的外面,必须写在循环里面Scanner sc = new Scanner(System.in);for (int i = 0; i < arr.length; i++) {//创建汽车对象Car c = new Car();//录入品牌System.out.println("请输入汽车的品牌:");String brand = sc.next();c.setBrand(brand);//录入价格System.out.println("请输入汽车的价格:");int price = sc.nextInt();c.setPrice(price);//录入颜色System.out.println("请输入汽车的颜色:");String color = sc.next();c.setColor(color);//把汽车对象添加到数组当中arr[i]=c;}//3.遍历数组for (int i = 0; i < arr.length; i++) {Car car = arr[i];System.out.println(car.getBrand()+","+car.getPrice()+","+car.getColor());}}
}
1.2.3 练习三
Phone的javabeen包
package test6;public class Phone {private String brand;//品牌private int price;//价格private String color;//颜色public Phone(){}public Phone(String brand,int price,String color){this.brand = brand;this.price = price;this.color = color;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}
}
PhoneTest
package test6;public class PhoneTest {public static void main(String[] args) {//1.创建一个数组Phone[] arr = new Phone[3];//2.创建手机的对象Phone p1 = new Phone("xiaomi",1999,"white");Phone p2 = new Phone("huawei",4999,"blue");Phone p3 = new Phone("meizhu",2999,"red");//3.把手机对象添加到数组当中arr[0]=p1;arr[1]=p2;arr[2]=p3;//4.获取三部手机的平均价格int sum = 0;for (int i = 0; i < arr.length; i++) {//i索引 arr[i]元素(手机对象)Phone phone = arr[i];sum = sum + phone.getPrice();}//5.求平均值double avg = sum*1.0/arr.length;System.out.println(avg);}
}
1.2.4 练习四
GilFriend的javabeen包
package test7;public class GirlFriend {private String name;//姓名private int age; //年龄private String gender;//性别private String hobby;//爱好public GirlFriend() {}public GirlFriend(String name, int age, String gender, String hobby) {this.name = name;this.age = age;this.gender = gender;this.hobby = hobby;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public String getHobby() {return hobby;}public void setHobby(String hobby) {this.hobby = hobby;}
}
GirlFriendTest
package test7;public class GirlFriendTest {public static void main(String[] args) {//1.定义数组存入女朋友的对象GirlFriend[] arr = new GirlFriend[4];//2.创建女朋友的对象GirlFriend gf1 = new GirlFriend("小老板",22,"man","do the game");GirlFriend gf2 = new GirlFriend("麻瓜",24,"man","van the game");GirlFriend gf3 = new GirlFriend("马捞C",30,"man","乖乖站好");GirlFriend gf4 = new GirlFriend("阿克曼",18,"man","fk you");//3.把对象添加到数组当中arr[0]=gf1;arr[1]=gf2;arr[2]=gf3;arr[3]=gf4;//4.求和int sum =0;for (int i = 0; i < arr.length; i++) {GirlFriend gf = arr[i];//累加sum += gf.getAge();}//5.平均值int avg = sum/arr.length;//6.统计年龄比平均值低的有几个,打印他们的信息int count = 0;for (int i = 0; i < arr.length; i++) {GirlFriend gf = arr[i];if(gf.getAge()<avg){count++;System.out.println(gf.getName()+","+gf.getAge()+","+gf.getGender()+","+gf.getHobby());}}System.out.println("一共"+count+"个");}
}
1.3 键盘录入回顾
键盘录入:
第一套体系:
- nextInt();接收整数
- nextDouble();接收小数
- next();接收字符串
- 遇到空格,制表符,回车就停止接受。这些符号后面的数据就不会接受了
public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("请输入一个整数:");//123 123int num1 = sc.nextInt();//123System.out.println(num1);System.out.println("请输入第二个整数:");int num2 = sc.nextInt();//123System.out.println(num2);}
当next中出现空格时,可会给下一个键盘的数据接受,就不会做键盘录入
2.
public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("请输入一个字符串:");String str1 = sc.next();System.out.println(str1);System.out.println("请输入第二个字符串:");String str2 = sc.next();System.out.println(str2);}
第二套体系:
- nextLine();接收字符串
遇到回车才停止录入
public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("请输入一个字符串:");String line1 = sc.nextLine();System.out.println(line1);System.out.println("请输入第二个字符串:");String line2 = sc.nextLine();System.out.println(line2);}
但是重要的是,键盘录入的两套体系不能混用
弊端:
- 先用nextInt,再用nextLine会导致下面的nextLine接受不到数据
public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("请输入一个整数:");int num = sc.nextInt();//123+回车System.out.println(num);//123System.out.println("请输入第一个字符串:");String line = sc.nextLine();System.out.println(line);//录入不了,就结束了}
1.4 复杂对象数组练习
1.4.1 复杂练习一
思考要求1和2思路:
1.创建一个长度为3的数组2.创建学生对象3.把学生对象添加到数组当中4.再次创建一个学生对象5.唯一性判断5.1已存在---提示重复5.2不存在---添加学生对象6.添加学生对象6.1老数组已经存满6.2老数组没有存满
Student的javabeen包:
package test8;public class Student {private int id;private String name;private int age;public Student() {}public Student(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
Test实现要求1和2:
package test8;public class Test {public static void main(String[] args) {//1.创建一个数组用来储存学生对象Student[] arr = new Student[3];//2.创建学生对象并添加到数组当中Student stu1 = new Student(1,"zhangsan",23);Student stu2 = new Student(2,"lisi",24);//3.把学生对象添加到数组当中arr[0]=stu1;arr[1]=stu2;//要求1:再次添加一个学生对象,并在添加的时候进行学号的唯一性判断。Student stu4 = new Student(4,"zhaoliu",26);//唯一性判断//已存在--不用添加//不存在--就可以把学生对象添加进数组boolean flag = contains(arr,stu4.getId());if(flag){//已存在--不用添加System.out.println("当前id重复,请修改id后再进行添加");}else{//不存在--就可以把学生对象添加进数组//把stu4添加到数组当中//1.数组已经存满---只能创建一个新的数组,新数组的长度=老数组+1//2.数组没有存满--直接添加int count = getCount(arr);if(count==arr.length){//已经存满//创建一个新的数组,长度=老数组的长度+1//然后把老数组的元素,拷贝到新数组当中Student[] newArr = creatNewArr(arr);//把stu4添加进去newArr[count]=stu4;//要求2:添加完毕之后,遍历所有学生信息printArr(arr);}else{//没有存满//[stu1,stu2,null]//getCount获取到的是2,表示数组当中已经有了2个元素//还有一层意思:如果下一次要添加数据,就是添加到2索引的位置arr[count] = stu4;//要求2:添加完毕之后,遍历所有学生信息,这样写就与上方重复了//此时就又需要定义方法进行调用printArr(arr);}}}public static void printArr(Student[] arr){for (int i = 0; i < arr.length; i++) {Student stu = arr[i];if(stu!=null){System.out.println(stu.getId()+","+stu.getName()+","+stu.getAge());}}}//创建一个新的数组,长度=老数组的长度+1// 然后把老数组的元素,拷贝到新数组当中public static Student[] creatNewArr(Student[] arr) {Student[] newArr = new Student[arr.length+1];//循环遍历得到老数组中的每一个元素for (int i = 0; i < arr.length; i++) {//把老数组中的元素添加到新数组当中newArr[i]=arr[i];}//把新数组返回return newArr;}//定义一个方法判断数组中已经存了几个元素public static int getCount(Student[] arr){//定义一个计数器用来统计int count = 0;for (int i = 0; i < arr.length; i++) {if(arr[i]!=null){count++;}}//当循环结束之后,我就知道了数组中一共有几个元素return count;}//1.我要干嘛? 唯一性判断//2.我干这件事,需要什么才能完成?数组id//3.调用处是否需要继续使用方法的结果?public static boolean contains(Student[] arr,int id){//1 2 3 ----3是否存在for (int i = 0; i < arr.length; i++) {//依次获取到数组里面的每一个学生对象Student stu = arr[i];//如果没装满,stu获取的是null,用null调用其他的方法就会报错if(stu!=null){//获取数组学生的idint sid = stu.getId();//比较if(sid == id){return true;}}}//当循环结束之后,还没有找到一样的,那么就表示数组中要查找的id是不存在的。return false;}
}
1.4.2 复杂练习二
Test2实现需求3和4
package test8;public class Test2 {public static void main(String[] args) {//1.创建一个数组用来储存学生对象Student[] arr = new Student[3];//2.创建学生对象并添加到数组当中Student stu1 = new Student(1,"zhangsan",23);Student stu2 = new Student(2,"lisi",24);Student stu3 = new Student(3,"wangwu",25);//3.把学生对象添加到数组当中arr[0]=stu1;arr[1]=stu2;arr[2]=stu3;//要求3:通过id删除学生信息//如果存在,则删除,如果不存在,则提示删除失败。//要找到id在数组中对应的索引int index = getIndex(arr,2);if(index>=0){//如果存在,则删除arr[index]=null;//遍历数组printArr(arr);}else{//如果不存在,则提示删除失败System.out.println("当前id不存在,删除失败");}}//1.我要干嘛? 找到id在数组中的索引//2.我干这件事,需要什么才能完成?数组id//3.调用处是否需要继续使用方法的结果? 要public static int getIndex(Student[] arr,int id){for (int i = 0; i < arr.length; i++) {//依次得到每一个学生对象Student stu = arr[i];//对stu进行一个非空判断if(stu !=null){int sid = stu.getId();if(sid==id){return i;}}}//当循环结束之后,还没有找到就表示不存在return -1;}public static void printArr(Student[] arr){for (int i = 0; i < arr.length; i++) {Student stu = arr[i];if(stu!=null){System.out.println(stu.getId()+","+stu.getName()+","+stu.getAge());}}}
}
Test3实现要求5:
package test8;public class Test3 {public static void main(String[] args) {//1.创建一个数组用来储存学生对象Student[] arr = new Student[3];//2.创建学生对象并添加到数组当中Student stu1 = new Student(1,"zhangsan",23);Student stu2 = new Student(2,"lisi",24);Student stu3 = new Student(3,"wangwu",25);//3.把学生对象添加到数组当中arr[0]=stu1;arr[1]=stu2;arr[2]=stu3;//4.先要找到id为2的学生对于的索引int index = getIndex(arr,2);//5.判断索引if(index>=0){//存在,则将他的年龄+1岁Student stu = arr[index];//把原来的年龄拿出来int newAge = stu.getAge()+1;//把+1之后的年龄塞回去stu.setAge(newAge);//遍历数组printArr(arr);}else{//不存在,则直接提示System.out.println("当前id不存在,修改失败");}}//1.我要干嘛? 找到id在数组中的索引//2.我干这件事,需要什么才能完成?数组id//3.调用处是否需要继续使用方法的结果? 要public static int getIndex(Student[] arr,int id){for (int i = 0; i < arr.length; i++) {//依次得到每一个学生对象Student stu = arr[i];//对stu进行一个非空判断if(stu !=null){int sid = stu.getId();if(sid==id){return i;}}}//当循环结束之后,还没有找到就表示不存在return -1;}public static void printArr(Student[] arr){for (int i = 0; i < arr.length; i++) {Student stu = arr[i];if(stu!=null){System.out.println(stu.getId()+","+stu.getName()+","+stu.getAge());}}}}
2. API:应用程序编程接口
例子:
其他的API都是存储在JDK-API帮助文档.CHM
2.1 使用帮助文档
API使用步骤
java.lang
包(非常重要)使用java.lang
包时,不需要import进行导入
API帮助文档网站
可以寻找关键字
API文档练习
public static void main(String[] args) {//1.创建对象Scanner sc = new Scanner(System.in);System.out.println("请输入一个小数:");//2.接受一个小数double result = sc.nextDouble();//3.输出打印System.out.println(result);}
3. 字符串String
常见情况:
字符串概述:
注意:
总结:
3.1 创建String对象的两种方式
其有两种:
直接赋值和用new去构造一个方法
public static void main(String[] args) {//直接赋值String a="1111";//空参构造String b=new String();System.out.println("1"+b+"2");//传递字符串(了解)String c=new String("abc");//传递字符数组//应用环境:修改字符串 例如把abc 改成qbc//abc-->{'a','b','c'}-->{'q','b','c'}-->""qbcchar[] d={'w','s','s','b'};String e=new String(d);System.out.println(e);//传递字节数组//应用场景:在网络中传输的都是字节信息,把字节信息转换成字符串byte[] f={97,98,99,100};//这里不是把数字传递过去,而是把数字转成ASCLL表里的字符。String g=new String(f);System.out.println(g);}
字符串在内存中的存储方式
字符串常量池
只有直接赋值的字符串才会在这个空间中 在堆内存中
当串池中已经存在一个abc字符串时,再次给字符串变量赋值相同的值时,会直接复用之前相同字符串的地址。
每new一次,就会在堆空间创建一个新的空间,可能会造成内存的浪费
所以,还是推荐使用直接赋值创建字符串。
3.2 字符串的比较
==号比较的原理
字符串常见比较错误:
对于不同方式字符串的内容比较:
例如:
1.
public static void main(String[] args) {//1.创建两个字符串对象String s1 = new String("abc");String s2 = "Abc";//2.==号比较//基本数据类型:比的是数据值//应用数据类型:比的是地址值System.out.println(s1==s2);//false//3.比较字符串对象中的内容是否相等boolean result = s1.equals(s2);System.out.println(result);//4.比较字符串对象中的内容是否相等,忽略大小写boolean result2 = s1.equalsIgnoreCase(s2);System.out.println(result2);// true}
public static void main(String[] args) {//1.假设我现在键盘录入一个abcScanner sc = new Scanner(System.in);System.out.println("请输入一个字符串:");String str1 = sc.next();//abc 是new出来的//2.代码中再定义一个字符串abcString str2 = "abc";//3.用==比较,这两者能一样吗?System.out.println(str1 == str2);//false,为什么?直接赋值的和new出来的不一样//结论://以后只要想比较字符串的内容,就必须要用string里面的方法}
3.3 字符串练习
3.3.1 练习一:用户登录
public static void main(String[] args) {// 1.定义两个变量记录正确的用户名和密码String rightUsername = "zhangsan";String rightPassword = "123456";Scanner sc =new Scanner(System.in);//2.键盘录入用户名和密码for (int i = 0; i < 3; i++) {System.out.println("请输入用户名:");String username = sc.next();System.out.println("请输入密码:");String password = sc.next();//3.比较if(username.equals(rightUsername)&&password.equals((rightPassword))){System.out.println("用户登录成功");break;}else{if(i==2){// 最后一次机会也输入错误,此时要提示账号被锁定System.out.println("账号"+username+"被锁定");}else{System.out.println("用户登录失败,用户名或密码有误,您还剩下"+(2-i)+"次机会");//}}}}
3.3.2 练习二 ctrl+alt+v 自动生成左边赋值
chcharAt()方法:返回每一个索引对应的索引值
public static void main(String[] args) {// 1. 键盘录入一个字符串Scanner sc = new Scanner(System.in);System.out.println("请输入一个字符串:");String str = sc.next();//2.进行遍历for (int i = 0; i < str.length(); i++) {//i 依次表示字符串的每一个索引//chcharAt()方法:返回每一个索引对应的索引值// ctrl+alt+v 自动str.charAt(i);生成左边char c = str.charAt(i);System.out.println(c);}
2.
public static void main(String[] args) {// 1. 键盘录入一个字符串Scanner sc = new Scanner(System.in);System.out.println("请输入一个字符串:");String str = sc.next();//2.统计---计数器思想//定义三个计数器int bigCount = 0;int smallCount = 0;int numberCount = 0;for (int i = 0; i < str.length(); i++) {//i 依次表示字符串中的每一个索引char c = str.charAt(i);if(c>='a'&&c<='z'){//char类型的变量在参与计算的时候自动类型提升为int查询ascii码表smallCount++;}else if(c>='A'&&c<='Z'){bigCount++;}else if(c>='0'&&c<='9'){numberCount++;}}System.out.println("小写字母有:"+smallCount+"个");System.out.println("大写字母有:"+bigCount+"个");System.out.println("数字字母有:"+numberCount+"个");}
3.3.3 练习三:字符串拼接和反转
public static void main(String[] args) {//1.我要干嘛?---遍历数组并把数组拼接成一个字符串//2.我干这件事情需要什么才能完成?---数组//3.我干完了是否要把结果返回给调用处---返回一个拼接之后的字符串// 如果调用处需要继续使用,那么必须返回//如果调用处不需要继续使用,那么可以返回也可以不返回int[] arr={1,2,3};String str = arrToString(arr);System.out.println(str);//123}public static String arrToString(int[] arr){if(arr==null){return"";}if(arr.length==0){return "[]";}String result = "[";//当代码执行到这里表示什么?//表示数组不是null,也不是长度为0的for (int i = 0; i < arr.length; i++) {if(i==arr.length-1){result = result+arr[i];}else{result = result+arr[i]+",";}}//此时拼接右括号result = result + "]";return result;}
2.
public class ArithmeticoperatorDemo1 {public static void main(String[] args) {String result = reverser("cnm");System.out.println(result);}public static String reverser(String str){String result = "";for (int i = str.length()-1; i >=0; i--) {char c = str.charAt(i);result += c;}return result;}
}
3.3.4 练习四
3.3.5 练习五
3.4 StringBuilder
使用StringBuilder的场景:
- 1.字符串的拼接
- 2.字符串的反转
相当于一个字符串的工具,StringBuilder不是字符串类型!!!!
3.4.1 StringBuilder构造方法
3.4.2 StringBuilder常用方法
1.append 添加方法
public static void main(String[] args) {//1.创建对象StringBuilder sb = new StringBuilder();//打印//普及://因为stringBuilder是Java已经写好的类// java在底层对他做了一些特殊处理。//打印对象不是地址值而是属性值。System.out.println(sb);}
所以它没有返回一个地址值
public static void main(String[] args) {//1.创建对象StringBuilder sb = new StringBuilder("abc");//2.添加元素sb.append(1);sb.append(2.3);sb.append(true);System.out.println(sb);}
2.reverse 反转方法
sb.reverse();
3.length 获取长度方法
int len = sb.length();System.out.println(len);
4.toString
public static void main(String[] args) {//1.创建对象StringBuilder sb = new StringBuilder("abc");//2.添加字符串sb.append("aaa");sb.append("wwww");sb.append("xxxx");System.out.println(sb);//abcaaawwwwxxxx只是在一个容器里面//3.再把StringBuilder变回字符串类型String str = sb.toString();System.out.println(str);//现在的abcaaawwwwxxxx才是字符串类型}
3.4.3 链式编程
当我们在调用一个方法的时候,不需要用变量接收他的结果,可以继续调用其他方法
1.
public static void main(String[] args) {String len = getString().substring(1).replace('b','w');System.out.println(len);int len2 = len.length();System.out.println(len2);}public static String getString(){Scanner sc = new Scanner(System.in);System.out.println("请输入一个字符串:");String str = sc.next();return str;}
2.
将上方3.4.2内容的第4点:
sb.append("aaa");sb.append("wwww");sb.append("xxxx");
可写成->一条链子,效果相同
sb.append("aaa").append("wwww").append("xxxx");
练习:
1.
equals() 方法用于比较两个字符串的内容是否相等。
package com.itheima.demo1;import java.util.Scanner;public class ArithmeticoperatorDemo1 {public static void main(String[] args) {// 1.键盘录入字符串Scanner sc = new Scanner(System.in);System.out.println("请输入一个字符串:");String str = sc.next();//2.反转键盘录入的字符串String result = new StringBuilder().append(str).reverse().toString();//.3比较if(str.equals(result)){System.out.println("当前字符串是对称字符串");}else{System.out.println("当前字符串不是对称字符串");}}
}
2.
package com.itheima.demo1;public class ArithmeticoperatorDemo1 {public static void main(String[] args) {//1.定义数组int[] arr = {1, 2, 3, 4};//2.定义一个接受字符数组的子函数,把arr放进去String str = arrString(arr);System.out.println(str);}public static String arrString(int[] arr) {//3. new一个StringBuilder容器,用来存放字符串StringBuilder sb = new StringBuilder();sb.append("[");//将 [ 先加入到容器中//4.循环遍历分割数组for (int i = 0; i < arr.length; i++) {//5.采用判断语句,如果加入到了最后一个字时,就i=length-1,才会不打印 , 逗号//其他加入的时候,就带 ,逗号一加入进容器if (i == arr.length - 1) {sb.append(arr[i]);} else {sb.append(arr[i]).append(",");}}//循环结束之后,填右边括号sb.append("]");//6.完成后返回sb的字符串类型return sb.toString();}
}
3.4.4 StringJoiner
对于有时候StringBuilder按照数组拼接字符串的时候就比较麻烦了,中间有的时候拼,有的时候不拼
StringJoiner概述:
StringJoiner对象的创建
StringJoiner的成员方法
1.add() 添加内容
delimiter:中间间隔的符号,prefix:开始的符合,suffix:结尾的符号
public static void main(String[] args) {StringJoiner sj = new StringJoiner("-----");//2.添加元素sj.add("aaa").add("bbbb").add("ccc");//3.打印结果System.out.println(sj);}
2.
public static void main(String[] args) {StringJoiner sj = new StringJoiner(",","[","]");//2.添加元素sj.add("aaa").add("bbbb").add("ccc");int len = sj.length();System.out.println(len);//14//3.打印结果System.out.println(sj);//容器的类型String str = sj.toString();System.out.println(str);//字符串的类型}
总结:
3.4.5 字符串原理
扩展底层原理1和2:字符串原理
扩展底层原理3:字符串拼接的底层原理
1.当等号的右边没有变量时:
在编译的时候,就会将"a"+ “b” +“c"拼接为"abc”
2.当等号的右边有变量时:
-
在jdk8以前:系统底层会自动创建一个StringBuilder对象,然后再调用其append方法完成拼接。
拼接后,再调用其toString方法转换为String类型,而toString方法的底层是直接new了一个字符串对象。 -
在jdk8之后:在编译时,会先预估字符串的长度并创建一个数组,再把数组变成一个字符串,这样就消耗性能了。
面试练习题:
2.
那就采用StringBuilder 和StringJoiner 进行优化
扩展底层原理5:StringBuilder提高效率原理
stringBuilder是一个内容可变的容器,所有要拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存
3、4原理小结:
扩展底层原理5:StringBuilder源码分析
总结:
ctrl + n IDEA快捷键 出现搜索界面
在所有位置里寻找,搜索界面默认在当前项目文件里找不到
--------->
ctrl + f12 ---->寻找toString
3.4.6 字符串综合练习
2.
3.
4. 集合
集合是一个容器,可以用来存储数据,和数组不同的是,集合的长度可以发生变化。当添加元素时,会自动扩容。
- 集合可以存储引用数据类型,不能直接存储基本数据类型,要把基本数据类型变成其对应的包装类才能存储。
4.1 ArrayList 集合(之一)
ArrayList集合的创建:
public static void main(String[] args) {//1.创建集合的对象//泛型:指限定集合中存储数据的类型,就是 <里面的>//ArrayList<String> list = new ArrayList<String>();// jDK7之后:ArrayList<String> list = new ArrayList<>();System.out.println(list);//此时我们创建的是ArrayList的对象,//这个类在底层做了一些处理//打印对象不是地址值,而是集合中存储数据内容 也就是[]//在展示的时候会拿[]把所有的数据进行包裹}
ArrayList成员方法
- add()和remove的返回值都是布尔值,add默认返回true,不用管,而remove在删除成功时返回true,失败时返回false
同时,remove还可以根据索引进行删除,返回值是被删除的元素 - set是修改指定索引上的值,返回被覆盖的值。
- get就是获取相应索引的元素
- size就是集合的长度,类似于length
public static void main(String[] args) {//1.创建集合的对象ArrayList<String> list = new ArrayList<>();//2.添加元素list.add("aaa");list.add("aaa");list.add("www");list.add("ddd");System.out.println("2:"+list);//3.删除元素boolean result1 = list.remove("aaa");System.out.println("3:"+result1);//当要删除的元素不存在时,就会falseSystem.out.println("3:"+list);//把被删除的元素进行返回String str = list.remove(2);System.out.println("3:"+str);System.out.println("3:"+list);//4.修改元素String res = list.set(1, "cccc");//把替换的元素进行返回System.out.println("4:"+res);System.out.println("4:"+list);//5.查询元素String s = list.get(0);System.out.println("5:"+s);System.out.println("5:"+list);//6.遍历元素 list.forifor (int i = 0; i < list.size(); i++) {//list.get(i) 元素String s1 = list.get(i);System.out.println("6:"+s1);System.out.println("6:"+list);}}
4.2 集合综合练习
4.2.1 添加字符串和整数遍历
public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");//遍历System.out.print("[");for (int i = 0; i < list.size(); i++) {if(i==list.size()-1){System.out.print(list.get(i));}else{System.out.print(list.get(i)+",");}}System.out.println("]");}
2.
下方遍历代码一样,中间改变
ArrayList<Integer> list = new ArrayList<>();list.add(1);list.add(2);list.add(3);list.add(4);list.add(5);
添加字符类型遍历也是同理
ArrayList<Character> list = new ArrayList<>();list.add('a');list.add('b');list.add('c');list.add('d');
4.2.2 基本数据类型的包装类
这里的包装类实际上就是泛型里的关键字
jdk5以后int Intleger 之间是可以互相转化的
4.2.3 添加学生对象并遍历
public static void main(String[] args) {ArrayList<Student> list = new ArrayList<>();//2.创建学生对象Student s1 = new Student("zhangsan",23);Student s2 = new Student("magua",24);Student s3 = new Student("xiaolaoban",25);//3.添加元素list.add(s1);list.add(s2);list.add(s3);//4.遍历集合for (int i = 0; i < list.size(); i++) {Student stu = list.get(i);System.out.println(stu.getName()+","+stu.getAge());}}
2.
遍历思路:
public static void main(String[] args) {ArrayList<Student> list = new ArrayList<>();// 长度为0//2.键盘录入学生的信息并添加到集合当中Scanner sc = new Scanner(System.in);for (int i = 0; i < 3; i++) {Student s = new Student();System.out.println("请输入学生的姓名:");String name = sc.next();System.out.println("请输入学生的年龄:");int age = sc.nextInt();//把name和age赋值给学生对象s.setName(name);s.setAge(age);//把学生对象添加到集合当中list.add(s);}//集合里面是否有学生对象//有? 没有?System.out.println(list.size());//3for (int i = 0; i < list.size(); i++) {Student stu = list.get(i);System.out.println(stu.getName()+","+stu.getAge());}}
4.2.4 添加用户对象并判断是否存在
javabean部分:
package test10;public class User {private String id;private String username;private String password;public User() {}public User(String id, String username, String password) {this.id = id;this.username = username;this.password = password;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}
Test部分:
package test10;import java.util.ArrayList;public class test {public static void main(String[] args) {//1.创建集合ArrayList<User> list = new ArrayList<>();//2.创建三个用户对象User u1 = new User("magua001","zhangsan","12345");User u2 = new User("magua002","lisi","12345678");User u3 = new User("magua003","wangwu","12345asd");//3.把用户对象添加到集合当中list.add(u1);list.add(u2);list.add(u3);//4.调用方法查看id是否存在boolean flag = contains(list, "magua001");System.out.println(flag);}public static boolean contains(ArrayList<User> list,String id){
// for (int i = 0; i < list.size(); i++) {
// User u = list.get(i);
// String uid = u.getId();
// if(uid.equals(id)){
// //如果找到了直接返回true
// return true;
// }
// }
// //当循环结束表示集合里面所有的元素都比较完毕还没有一样的
// //那么就返回false
// return false;return getIndex(list,id)>=0;}public static int getIndex(ArrayList<User>list,String id){for (int i = 0; i < list.size(); i++) {User u = list.get(i);String uid = u.getId();if(uid.equals(id)){return i;}}return -1;}
}
4.2.5 添加手机对象并返回要求的数据
phone的javabean:
package test11;public class Phone {private String brand;private int price;public Phone() {}public Phone(String brand, int price) {this.brand = brand;this.price = price;}public String getBrand() {return brand;}public void setBrand(String brand) {this.brand = brand;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}
}
test部分:
public static void main(String[] args) {//1.创建集合ArrayList<Phone> list = new ArrayList<>();//2.创建三个用户对象Phone p1 = new Phone("xiaomi",1000);Phone p2 = new Phone("iphone",4000);Phone p3 = new Phone("cuizi",2000);//3.把用户对象添加到集合当中list.add(p1);list.add(p2);list.add(p3);//4.调用方法ArrayList<Phone> phoneInfoList = getPhoneInfo(list);//5.遍历集合for (int i = 0; i < phoneInfoList.size(); i++) {Phone phone = phoneInfoList.get(i);System.out.println(phone.getBrand()+","+phone.getPrice());}}//1.我要干嘛?查询手机信息//2.我干这件事情,需要什么才能完成?集合//3.我干完了,方法的调用处是否需要继续使用结果?返回//技巧://如果我们要返回多个数据,可以把这些数据先放到一个容器当中,再把容器返回/集合数组public static ArrayList<Phone> getPhoneInfo(ArrayList<Phone> list){//定义一个集合用于存储价格低于3000的手机对象ArrayList<Phone> resultList = new ArrayList<>();//遍历集合for (int i = 0; i < list.size(); i++) {Phone p = list.get(i);int price = p.getPrice();//如果当前手机的价格低于3000,if(price<3000){resultList.add(p);}}return resultList;//返回的是集合,函数的返回值类型就得是集合}
5. 学生管理系统
学会阅读需求文档,在了解需求文档后,自己画出需求的结构流程图(业务流程图)
流程图:
Ctrl + alt + t 全选中内容后,快捷生成结构环绕方式
StudentTest第一部分:
package test1;import java.util.ArrayList;
import java.util.Scanner;public class StudentTest {public static void main(String[] args) {ArrayList<Student> list = new ArrayList<>();while (true) {//不要把ArrayList<Student> list = new ArrayList<>();//放在循环内部,这样在添加学生到list后,再循环一次,list又变成了0,这样查询的时候就总是无法查到System.out.println("----------------欢迎来到小黑子的学生管理系统----------------");System.out.println("1:添加学生");System.out.println("2:删除学生");System.out.println("3:修改学生");System.out.println("4:查询学生");System.out.println("5:退出");System.out.println("请输入您的选择:");Scanner sc = new Scanner(System.in);//定义一个字符串来接收String choose = sc.next();switch (choose) {case "1" -> addStudnet(list);case "2" -> deleteStudnet(list);case "3" -> updateStudnet(list);case "4" -> queryStudnet(list);case "5" -> {System.out.println("退出");System.exit(0);//停止虚拟机运行}default -> System.out.println("没有这个选项");}}}//添加学生public static void addStudnet(ArrayList<Student> list) {//利用空参构造先创建学生对象Student s = new Student();Scanner sc = new Scanner(System.in);String id = null;while (true) {System.out.println("请输入学生的id:");id = sc.next();boolean flag = contains(list, id);if (flag) {//true 表示id已经存在,需要重新录入System.out.println("id已经存在,请重新录入");} else {//表示id不存在,唯一s.setId(id);break;}}System.out.println("请输入学生的姓名:");String name = sc.next();s.setName(name);System.out.println("请输入学生的年龄:");int age = sc.nextInt();s.setAge(age);System.out.println("请输入学生的家庭住址:");String address = sc.next();s.setAddress(address);//把学生对象添加到集合当中list.add(s);//提示用户System.out.println("学生信息添加成功");System.out.println(list.size());}//删除学生public static void deleteStudnet(ArrayList<Student> list) {Scanner sc = new Scanner(System.in);System.out.println("请输入要删除的id:");String id = sc.next();//查询id在集合中的索引int index = getIndex(list, id);//对index进行判断//如果-1,就表示索引不存在,结束方法,返回初始菜单if (index >= 0) {//如果大于等于0的,表示存在,直接删除list.remove(index);System.out.println("id为:" + id + "的学生删除成功");} else {System.out.println("id不存在,删除失败");}}//修改学生public static void updateStudnet(ArrayList<Student> list) {Scanner sc = new Scanner(System.in);System.out.println("请输入要修改学生的id:");String id = sc.next();int index = getIndex(list,id);if(index == -1){System.out.println("要修改的id:"+id+"不存在,请重新输入");return;}//当代码执行到这里,表示什么?表示当前id是存在的//获取要修改的学生对象Student stu = list.get(index);//输入其他的信息并修改System.out.println("请输入修改的学生姓名:");String newName = sc.next();stu.setName(newName);System.out.println("情输入修改的学生年龄:");String newAge = sc.next();stu.setName(newAge);System.out.println("情输入修改的学生家庭住址:");String newAddress = sc.next();stu.setName(newAddress);System.out.println("学生信息修改完成");}//查询学生public static void queryStudnet(ArrayList<Student> list) {System.out.println(list.size());if (list.size() == 0) {System.out.println("当前无学生信息,请添加后再查询");return;}//打印表头信息System.out.println("id\t\t姓名\t年龄\t家庭住址");//当代码执行到这里时表示集合是有数据的,遍历集合的每个数据for (int i = 0; i < list.size(); i++) {Student stu = list.get(i);System.out.println(stu.getId() + "\t" + stu.getName() + "\t" + stu.getAge() + "\t" + stu.getAddress());}}//判断id 的方法public static boolean contains(ArrayList<Student> list, String id) {
// //循环遍历每一个学生对象
// for (int i = 0; i < list.size(); i++) {
// //拿到学生对象后,获取id并进行判断
// Student stu = list.get(i);
// String sid = stu.getId();
// if(sid.equals(id)){
// //存在,true
// return true;
// }
// }
// //不存在方法就返回false
// return false;return getIndex(list, id) >= 0;}//通过id获取索引的方法public static int getIndex(ArrayList<Student> list, String id) {//遍历集合for (int i = 0; i < list.size(); i++) {//得到每一个学生对象Student stu = list.get(i);//得到每一个学生对象的idString sid = stu.getId();//拿着集合中的学生id跟要查询的id进行比较if (sid.equals(id)) {//如果一样,那么就返回索引return i;}}return -1;}
}
swich语句不能用箭头表达式,java版本换成jdk17以上行了。
5.1 学生管理系统升级版
需求图:
流程图:
1.注册
2.登录
3.忘记密码
6. 面向对象进阶
6.1 static
6.1.1 static-静态变量
static(静态变量)(静态变量被该类所有对象共享),是Java中的一个修饰符,可以修饰成员方法,成员变量
javabean类:
public class Student {private String name;private int age;private String gender;public static String teacherName;public Student() {}public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}//行为public void study(){System.out.println(name+"正在学习");}public void show(){System.out.println(name+","+age+","+gender+","+teacherName);}
测试类:
public static void main(String[] args) {//1.创建学生对象Student s1 = new Student();s1.setName("张三");s1.setAge(23);s1.setGender("man");s1.teacherName = "麻瓜";s1.study();s1.show();//2.创建第二个学生对象Student s2 = new Student();s2.setName("李四");s2.setAge(25);s2.setGender("man");s2.study();s2.show();}
当这里的teacherName被赋值后,static会被Student类里所有对象共享(公共的一个属性)
静态变量是随着类的加载而加载的,优先于对象出现,被赋值是单独存储再堆内存中的静态区域
示意图:
静态区里的变量是对象共享的,在内存中只有一份,谁用谁拿,非静态的变量是每一个对象所独有的,每一个对象里的非静态的变量都是单独存放的。
判断一个变量是否是静态变量,主要就是两个字,共享
需要共享的变量就是静态变量
6.1.2 static-静态方法和工具
静态方法
工具类
工具类:帮助我们做一些事情的,但是不描述任何事物的类
目前一共学习了三种类
工具类的要求:
这里的第2个私有化构造方法
就是
public class Student {private public Student() {}
}
一个类一旦被私有化构造方法后,就不能创建这个类的对象了。
练习:
1.
javabean类:
public class ArrayUtil {//私有化构造方法//目的:为了不让外界创建他的对象private ArrayUtil(){}public static String printArr(int[] arr){//一到字符串的拼接,就一定要想到StringBuildeStringBuilder sb = new StringBuilder();sb.append("[");for (int i = 0; i < arr.length; i++) {if(i==arr.length-1){sb.append(arr[i]);}else{sb.append(arr[i]).append(", ");}}sb.append("]");return sb.toString();}public static double getAverage(double[] arr){double sum =0;for (int i = 0; i < arr.length; i++) {sum = sum + arr[i];}return sum/arr.length;}
}
测试类:
public class TestDemo {public static void main(String[] args) {//测试工具类的两个方法是否正确int[] arr1 = {1, 2, 3, 4, 5};String str = ArrayUtil.printArr(arr1);System.out.println(str);double[] arr2 ={1.5,23.43,654.43,1.23,23.3};double avg = ArrayUtil.getAverage(arr2);System.out.println(avg);}
}
2.
工具类:
import java.util.ArrayList;public class StudentUtil {private StudentUtil(){}//静态方法public static int getMaxAgeStudent(ArrayList<Student> list){//1.定义一个参照物int max = list.get(0).getAge();//2.循环遍历集合for (int i = 0; i < list.size(); i++) {//i 索引 list.get(i)元素/学生对象 我们还需要getAge获取到年龄之后再进行比较int tempAge = list.get(i).getAge();if(tempAge>max){max = tempAge;}}//3.直接返回return max;}
}
Test部分调用工具类方法:
//4.调用工具类方法int maxAgeStudent = StudentUtil.getMaxAgeStudent(list);System.out.println(maxAgeStudent);
6.1.3 static-注意事项
在非静态方法中,有一个隐藏的this,这个this就表示当前方法调用者的地址值
在第一次调用show()方法时,虚拟机就会把第一次调用者的地址赋值给方法中的this,就像图中所示
第二次同理,虚拟机会把第二次调用者的地址赋值给方法中的this
this的值
this的这一特性就是区分不同对象的 即在调用成员变量时,变量前面有隐含的this,从而显示出不同变量的结果
上面sout里的this可以省略
- 而在static静态方法中,是没有这个this关键字的
- 原因就是静态方法是公用的,而this一般是独立的对象进行使用,不符合公用的理念。
示意图:
- 静态方法不能访问非静态成员变量(也就是实例变量即对象)
因为在使用静态方法时,通过类名调用会直接到静态存储位置去找变量,而非静态的变量是随着对象的创建而创建的,在静态存储位置找不到,所以静态方法不能调用非静态成员变量
- 静态方法不能访问非静态的成员方法
因为非静态的方法需要调用者,而在静态方法中是没有this的,也就没有调用者,自然就不能使用了
综上,静态方法只能调用静态的内容
- 非静态方法可以访问所有
因为静态的是公用的,所以非静态既可以访问到静态,也可以访问非静态
小结:
6.1.4 重新认识main方法
JVM:虚拟机
例子:
点击IDEA右上角的锤子旁边的按钮
在程序参数里填写,args即可返回值
6.2 继承
6.2.1 封装
封装:
对象代表什么,就得封装对应的数据,并提供数据对应的行为
像这种相同的行为太多了,这时候就需要用到封装
封装完行为方法之后,就要用到继承了
6.2.2 继承的描述
继承实际上就是类跟类之间的父子关系
什么时候用继承?
小结:
继承需要学习的点:
6.2.3 继承的特点
即儿子继承父亲,父亲继承爷爷
即子类的父类是直接父类,父类的父类是子类的间接父类
java中有一个祖宗类就是Object,每一个类都直接或间接继承于Object
小结:
练习:
设计继承体系时,尽量先搞清楚体系逻辑,画一张图,从子类到父类
设计的核心就是:共性的内容抽取,子类是父类的一种
书写代码时,从父类到子类
小结:
6.2.4 子类继承父类的特性
-
构造方法:不论私有(private)还是非私有(像public等)的构造方法,子类都是不能继承的
例子:
-
成员变量:不论私有(private,不能直接调用)还是非私有(像public等)的成员变量,子类都是可以继承的(相当于从父类哪里copy了一份过来)
1.没有用private修饰的继承成员变量的内存图:
2.有用private修饰的继承成员变量的内存图:
- 这里new出来一个子类后,会把堆内存中开辟出来的空间分为两部分,第一部分是继承父类的成员变量,第二类是子类自己的成员变量
- 如果父类的成员变量使用private修饰后,子类对象在堆内存中就无法使用继承父类的成员变量。
父类会把非private,非static和非final的方法(这些方法统称为虚方法)抽取出来,放到虚方法表里,在继承的时候,父类会把虚方法表交给子类复制,子类可以添加新的虚方法加入到子类的虚方法表中,使后代继续复制
- 成员方法:非私有的成员方法(虚方法)可以被继承,私有的成员方法就不能被继承下来
运行效率低下:
以下如此可以大大提高性能:
例子:
6.2.5 终端的jps和jhsdb hsdb
在终端中输入jps,得到类中获得的id
输入jhsdb hsdb 打开HotSpot Debugger
- (HSDB(Hotspot Debugger) ,是一款内置于 SA 中的 GUI 调试工具,可用于调试 JVM运行时数据,从而进行故障排除。)
在file中寻找到第一个点击进入
从jps中获得的id输入,ok
之后显示
在tools里找到Memory Viewer
在tools里找到Inspector
6.2.6 继承中成员变量和成员方法的访问特点
继承成员变量
- 继承的成员变量的访问特点: 就近原则:
谁离我近,我就用谁
即优先级为: 方法内的成员变量>子类的成员变量>父类的成员变量
在使用一个成员变量时,会先在局部的方法内找,如果方法内没有,就会到本类(子类)中去找,本类中再没有,就会到父类中去找
在上述代码中,name就是“ziShow”,如果“ziShow”没有,name就是“Zi”,如果“Zi”再没有,那么name就是“Fu”
当然,也可以同时访问这三个成员变量
例子:
1.
public class Test {public static void main(String[] args) {Zi zi=new Zi();zi.ziShow();}
}
class Fu{String name="Fu";
}
class Zi extends Fu{String name="Zi";public void ziShow(){String name="ziShow";System.out.println(name);System.out.println(this.name);System.out.println(super.name);}
}
2.
即使用this关键字可以访问本类的成员变量,使用super关键字可以访问父类的成员变量。
语法:
- this.变量名
- super.变量名
注:在子类中最多使用一个super
小结:
继承成员方法
继承的成员方法的访问特点:
- 直接调用:满足就近原则,谁近调用谁
- super调用:直接访问父类
与上面成员变量的特点一样,都是就近原则,都是this,super
public class Test {public static void main(String[] args) {Zi zi=new Zi();zi.show();}
}
class Fu{String name="Fu";public void eat(){System.out.println("chifan,父类被调用");}
}
class Zi extends Fu{String name="Zi";//这里进行了方法的重写,由于父类的方法不能满足子类的需求,从而进行了方法的重写@Overridepublic void eat(){System.out.println("heshui,子类被调用");}public void show(){eat();this.eat();super.eat();}
}
方法重写的本质:
新的方法覆盖旧的方法(虚方法表)
方法重写注意事项和要求:
私有方法不能进行重写,重写方法时也可以调用父类的方法
练习:
总结:
6.2.6 继承中的构造方法
- 特点
1.父类中的构造方法不会被子类继承
2.子类中所有的构造方法默认先访问父类中的无参构造,再执行自己
第二条出现的原因
例子:
所以,子类的构造方法的第一句都会是
super()
,即使不写也会存在于第一行。 这里的super()
就是调用父类的空参构造方法
如果想调用父类的有参构造,就必须手动写super进行调用
小结:
6.2.7 this、super关键字总结
- this 就相当于一个局部变量,表示当前方法调用者的地址值
- super 就代表父类的存储空间
this与super的区别:
关键字 | 访问成员变量 | 访问成员方法 | 访问构造方法 |
---|---|---|---|
this | this.成员变量 访问本类成员变量 | this.成员方法访问本类成员方法 | this(…)访问本类构造方法 |
super | super.成员变量 访问父类成员变量 | super. 访问父类成员方法 | super(…)访问父类构造方法 |
当使用this方法来访问本类构造方法:
public class Person {String name;int age;String gender;public Person() {this(null,0,"男");}public Person(String name,int age,String gender){this.name=name;this.age=age;this.gender=gender;}
}
这里空参构造里的this(null,0,"男")
;就是使用this来访问构造方法,并赋予初始值
且,使用this()
后,虚拟机就不会自动添加super()
了
练习:
Employeer:
public class Employee {//1.类名见名知意//2.所有的成员变量都需要私有//3.构造方法(空参带全部参数的构造)//4.get/ setprivate String id;private String name;private double salary;public Employee(){}public Employee(String id, String name, double salary) {this.id = id;this.name = name;this.salary = salary;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getSalary() {return salary;}public void setSalary(double salary) {this.salary = salary;}//工作public void work(){System.out.println("员工在工作");}//吃饭public void eat(){System.out.println("吃米饭");}
}Manager:
public class Manager extends Employee{private double bouns;//空参构造public Manager(double bouns) {this.bouns = bouns;}//带全部参数的构造//父类+子类public Manager(String id, String name, double salary, double bouns) {super(id, name, salary);this.bouns = bouns;}public double getBouns() {return bouns;}public void setBouns(double bouns) {this.bouns = bouns;}@Overridepublic void work() {System.out.println("管理其他人");}
}Cook:
public class Cook extends Employee{public Cook(){}public Cook(String id, String name, double salary) {super(id, name, salary);}@Overridepublic void work() {System.out.println("厨师正在炒菜");}
}Test:
public class Test {public static void main(String[] args) {//创建对象并赋值调用Manager m = new Manager("magua001","小笼包",15000,8000);System.out.println(m.getId()+","+m.getName()+","+m.getSalary()+","+m.getBouns());m.work();m.eat();Cook c = new Cook();c.setId("magua002");c.setName("lisi");c.setSalary(8000);System.out.println(c.getId()+","+c.getName()+","+c.getSalary());c.work();c.eat();}
}
6.3 认识多态
多态的概念:
封装是多态的必要条件,继承是多态的前提条件
多态的应用场景:
不同的用户对象,采用同样的代码模块会出现冗余
解决方案:
多态的含义
多种形态,同种类型的对象表现出的不同形态 可以以父类来创建子类对象,即使用父类型作为参数,可以接收所有子类对象
多态语法
父类类型 对象名称=子类对象
多态可以根据调用对象的不同,使用对应的方法
例如
Person man=new Student()
,这里Person是父类,Student是子类 但是多态的使用要满足以下前提
例子:
Person类:
public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void show(){System.out.println(name+","+age);}
}Student类:
public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void show(){System.out.println(name+","+age);}
}Teacher类:
public class Teacher extends Person{@Overridepublic void show() {System.out.println("老师的信息为:"+getName()+","+getAge());}
}Adminnistrator类:
public class Administrator extends Person{@Overridepublic void show() {System.out.println("管理员的信息为:"+getName()+","+getAge());}
}测试类:
public class Test {public static void main(String[] args) {//创建三个对象,并调用register方法Student s =new Student();s.setName("张三");s.setAge(18);Teacher t = new Teacher();t.setName("麻瓜");t.setAge(30);Administrator admin = new Administrator();admin.setName("管理员");admin.setAge(35);//不管传递什么对象,都可以被下方Person接收//这就是多态的原因register(s);register(t);register(admin);}//这个方法既能接收老师,又能接收学生,还能接收管理员// 只能把参数写成这三个类型的父类public static void register(Person p){p.show();}
}
总结:
6.3.1 多态中调用成员的特点
父类 对象名=new 子类()
遵循两个口诀:
-
编译看左边的解释: javac编译代码时,会看左边的父类有没有这个变量或方法,如果有,编译成功,如果没有,编译失败,即必须要有父类的方法
-
运行也看左边的解释: javac运行代码的时候,实际获取的就是左边父类中成员变量的值。
即对象调用遵循以上两个规则。
同理,方法调用也是如此,只不过在运行时会运行子类的方法,即右边
内存图解:
例子:
//父类Person
package com.inherit.study;public class Person {String name="人";int age;String gender;public Person() {}public Person(String name,int age,String gender){this.name=name;this.age=age;this.gender=gender;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public void show(){System.out.println(name+" "+age);}
}
//子类Student
package com.inherit.study;public class Student extends Person {String name="学生";@Overridepublic void show(){System.out.println("学生的信息为:"+getName()+" "+getAge());}
}
//测试类
package com.inherit.study;public class test3 {public static void main(String[] args) {Person pr=new Student();System.out.println(pr.name);pr.show();}}
可以看到,父类的成员变量显示出来,子类的成员变量没有显示,并且子类的方法被运行,父类的方法没有运行
子类的方法能运行的原因是子类重写的方法是虚方法,在虚方法表里覆盖了父类的虚方法。
如果是子类 对象名=子类()
这种形式调用成员变量时,会先在子类的内存空间寻找成员变量,子类的内存空间没有时,才会到父类的内存空间去找,这是继承的特性,而在多态中,父类 对象名=new 子类()
如果父类里没有相应的成员变量,会直接报错。
6.3.2 多态的优势和弊端
优势:
即只需把后面标红的代码修改就可以了
弊端:
- 不能调用子类的特有功能
- 因为子类的特有方法不是重写的,是子类独有的,父类里没有,所以不能调用,会报错。
解决方案:
用强制类型转换把父类型转换为子类型,不能随便转换,要对应着转换
例子:
public class Test {public static void main(String[] args) {//创建对象Animal a =new Dog();a.eat();//多态的弊端//不能调用子类的特有功能很错的原因?//当调用成员方法的时候,编译看左边,运行看右边//那么在编译的时候会先检查左边的父类中有没有这个方法,如果没有直接报错。//a.lookHome();Animal没有lookHome() 报错//解决方案://变回子类就可以了//Dog d =(Dog) a;//d.lookHome();//细节:转换的时候不能瞎转,如果转成其他类的类型,就会报错//Cat c = (Cat) a;//c.CatchMouse(); 已经new成狗了,就不能再变成猫}
}class Animal{public void eat(){System.out.println("动物在吃东西");}
}class Dog extends Animal{@Overridepublic void eat() {System.out.println("狗吃骨头");}public void lookHome(){System.out.println("狗看家");}
}class Cat extends Animal{@Overridepublic void eat() {System.out.println("猫吃小鱼干");}public void CatchMouse(){System.out.println("猫抓老鼠");}
}
6.3.3 instanceof 判断是不是相应类型
可以用instanceof
关键字来判断是不是相应类型
对象名 instanceof
类
如果是相应类型,会返回true,否则返回false
//可以利用判断语句进行判断类型是否转换if(a instanceof Dog){Dog d =(Dog) a;d.lookHome();} else if(a instanceof Cat){Cat c = (Cat) a;c.CatchMouse();}else{System.out.println("没有这个类型,无法转换");}
java14的新特性
对象名 instanceof 类 变量名
如果是相应类型,会直接变成相应类型的变量,否则结果是false
if(a instanceof Dog d){d.lookHome();} else if(a instanceof Cat c){c.CatchMouse();}else{System.out.println("没有这个类型,无法转换");}
小结:
6.3.4 多态综合练习
Animal类:
public class Animal {private int age;private String color;public Animal() {}public Animal(int age, String color) {this.age = age;this.color = color;}public void eat(String something){System.out.println("动物在吃"+something);}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getColor() {return color;}public void setColor(String color) {this.color = color;}
}Dog类:
public class Dog extends Animal{public Dog(){}public Dog(int age,String color){super(age,color);}//行为//eat(String something ) (something表示吃的东西)//看家lookHome方法(无参数)@Overridepublic void eat(String something) {System.out.println(getAge()+"岁的"+getColor()+"黑颜色的狗两只前腿死死的抱住"+something+"骨头猛吃");}public void lookHome(){System.out.println("狗在看家");}
}Cat类:
public class Cat extends Animal{public Cat() {}public Cat(int age, String color) {super(age, color);}@Overridepublic void eat(String something) {System.out.println(getAge()+"岁的"+getColor()+"黑颜色的狗两只前腿死死的抱住"+something+"骨头猛吃");}public void catchMouse(){System.out.println("猫抓老鼠");}
}Person类:
public class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}// //饲养狗
// public void keePet(Dog dog,String something){
// System.out.println("年龄为"+age+"岁的"+name+"养了一只"+dog.getColor()+"颜色的"+dog.getAge()+"岁的狗");
// dog.eat(something);
// }
// //饲养猫
// public void keePet(Cat cat,String something){
// System.out.println("年龄为"+age+"岁的"+name+"养了一只"+cat.getColor()+"颜色的"+cat.getAge()+"岁的猫");
// cat.eat(something);
// }//想要一个方法,能接收所有的动物,包括猫,包括狗//方法的形参,可以写这些类的父类 Animalpublic void keepPet(Animal a,String something){if(a instanceof Dog d){System.out.println("年龄为"+age+"岁的"+name+"养了一只"+a.getColor()+"颜色的"+a.getAge()+"岁的狗");d.eat(something);}else if(a instanceof Cat c){System.out.println("年龄为"+age+"岁的"+name+"养了一只"+c.getColor()+"颜色的"+c.getAge()+"岁的猫");c.eat(something);}else{System.out.println("没有这种动物");}}}测试类:
public class Test {public static void main(String[] args) {//创建对象并调用方法
// Person p = new Person("老王",30);
// Dog d = new Dog(2,"墨");
// p.keePet(d,"骨头");
//
// Person p2 = new Person("老李",25);
// Cat c = new Cat(4,"灰");
// p2.keePet(c,"鱼");Person p = new Person("老王",30);Dog d = new Dog(2,"黑");Cat c =new Cat(3,"灰");p.keepPet(d,"骨头");p.keepPet(c,"鱼");}
}
6.4 包和 final
6.4.1 包
包的起名规则:
公司域名反写+包的作用
包名加上类名才是全部的类名,下面的名字太长了
改进:如果想在一个包里使用其他包的类名,就需要引用使用的那个包的名字加上类名
import 包名.类名
这样就可以使用其他包的类了
注意事项:
使用两个包的同名类时,不需要导包了,直接使用同名类
小结:
6.4.2 final (与static类似的关键字)
在代码中,一旦被final修饰,就表示被修饰的内容不能改变了,有点像JavaScript的const。
final可以修饰方法,类,和变量
- 修饰方法时: 表示该方法是最终方法,不能被重写
- 修饰类时: 表示该类是最终类,不能被继承
- 修饰变量时: 这个变量就会变为一个常量,只能被赋值一次
使用final的场景:
如果定义的方法是一种规则时,可以用final 主要还是用final来修饰变量
常量:
主要是第二点,对象的内部可以改变。
字符串不可变的原因就是final和private
ieda快捷键 crtl+shift+u可以让字母变成大写
小结:
6.5 权限修饰符和代码块
6.5.1 权限修饰符
权限修饰符的分类:
有四种类,被访问的范围从小到大分为:private<空着不写(默认情况)<protected<public
修饰符 | 同一个类中的作用范围 | 同一个包里的其他类的作用范围 | 不同包下的子类的作用范围 | 不同包下的无关类的作用范围 |
---|---|---|---|---|
private | 可以 | 不行 | 不行 | 不行 |
空着不写(默认) | 可以 | 可以 | 不行 | 不行 |
protected | 可以 | 可以 | 可以 | 不行 |
public | 可以 | 可以 | 可以 | 可以 |
实际开发中,一般来讲,只会用private和public,且遵守以下规则:
6.5.2 代码块
代码块可以分为三类
局部代码块,构造代码块,静态代码块
- 局部代码块
作用:提前结束变量的生命周期(例如上面的a,代码块结束后,a就会消失)
这个技术现在已经用不到了
- 构造代码块(了解)
1.就是写在成员位置的代码块,可以优先于构造方法执行
2.作用:可以把多个构造方法中重复的代码抽取出来。
3.执行时机:我们在创建本类对象的时候会先执行构造代码块,再执行构造方法
这个技术现在也渐渐淘汰了
可以将重复的代码抽取成一个方法,构造方法需要使用时直接调用方法就行了。
- 静态代码块(重点)
就是在构造代码块的基础上加上static
小结:
6.6 抽象类和抽象方法
抽象类
下面每个子类的工作内容是不一样的,解决方法就是在子类中随便写一个方法乙,让子类再去重写。
但是有一个小弊端,下面的子类是别人写的代码,别人在写子类的时候忘了重写,那就没办法了。
所以,抽象关键字就来进行强制重写,否则代码就直接报错,抽象方法所在的类就叫抽象类。
抽象关键字:abstract
抽象类:
如果一个类中存在抽象方法,那么该类就必须声明为抽象类。(由方法推向类,不是由类推向方法)
抽象方法
抽象方法的定义格式:
public abstract 返回值类型 方法名(参数列表);
没有方法体
抽象类的定义同理:public abstract class 类名{}
抽象类和抽象方法的注意事项
1.抽象类不能创建对象
2.抽象类中不一定有抽象方法,有抽象方法的一定是抽象类
3.抽象类可以有构造方法(作用:当创建子类对象时给子类的属性进行赋值)
4.抽象类的子类分两种情况:
- 如果子类不是抽象类,则需要重写抽象类中的所有方法
- 如果子类是抽象类,则没事
ieda便捷键 alt+回车 可以查看报错的内容并且快速修改
练习:
Animal类:
public abstract class Animal {private String name;private int age;public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public void drink(){System.out.println("动物在喝水");}public abstract void eat();
}Frog类:
public class Frog extends Animal{public Frog() {}public Frog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("青蛙在吃虫子");}
}Dog类:
public class Dog extends Animal{public Dog(){}public Dog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("狗吃骨头");}
}Sheep类:
public class Sheep extends Animal{public Sheep() {}public Sheep(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("山羊在吃草");}
}测试类:
public class Test {public static void main(String[] args) {//创建对象Frog f =new Frog("mauga",1);System.out.println(f.getName()+","+f.getAge());f.drink();f.eat();}
}
抽象类和抽象方法的意义:
当每个关于同一个行为的代码不统一时,调用时就会非常痛苦
用抽象类进行重写
总结:
6.7 接口
接口就是一种规则,是指父类与子类之间的关系。
下述图片很好的说明了为什么要有接口:
接口的应用:
接口不代表一类事务,他代表一种规则,是对行为的抽象
接口与抽象的区别:
抽象更多是表示一类事物,而接口更多表示行为
接口的定义和使用:
1.接口用关键字interface
定义
public interface 接口名
{}
2.接口不能创建对象
3.接口和类是实现关系,通过inplements
关键字表示
public class 类名 inplements 接口名{}
4.接口的子类(接口的实现类)
分两种情况:
- 不是抽象类直接重写所有抽象方法(更多用这种)
- 是抽象类没事
5.接口里的方法都是抽象方法
练习:
创建新的类时选择接口的选项
Animal类:
public abstract class Animal {private String name;private int age;public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public abstract void eat();
}接口:
public interface Swim {public abstract void swim();
}Rabbit类:
public class Rabbit extends Animal{public Rabbit() {}public Rabbit(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("兔子在吃胡萝卜");}
}Frog类:
public class Frog extends Animal implements Swim{public Frog() {}public Frog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("青蛙在吃虫子");}@Overridepublic void swim() {System.out.println("青蛙在蛙泳");}
}Dog类:
public class Dog extends Animal implements Swim{public Dog() {}public Dog(String name, int age) {super(name, age);}@Overridepublic void eat() {System.out.println("狗吃骨头");}@Overridepublic void swim() {System.out.println("狗刨式");}
}测试类:
public class Test {public static void main(String[] args) {Frog f = new Frog("青蛙",1);System.out.println(f.getName()+","+ f.getAge());f.eat();f.swim();Rabbit r = new Rabbit("兔子",2);System.out.println(r.getName()+","+r.getAge());r.eat();}
}
6.7.1 接口的细节:成员特点和各种接口的关系
接口中成员的特点:
inter接口:
public interface Inter {//public static finalint a =10;//public abstractvoid method();
}InterImp1类:
public class InterImp1 implements Inter{@Overridepublic void method() {System.out.println("method");}
}测试类:
import java.util.Scanner;public class Test {public static void main(String[] args) {//创建实现对象并调用方法InterImp1 li = new InterImp1();li.method();Scanner sc = new Scanner(System.in);sc.next();//防止程序运行过快,无法反应}
}
接口和类之间的关系:
- 类和类之间的关系
继承关系,只能单继承,不能多继承,但是可以多重继承 - 类和接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。
多个接口中有重名的方法,只需在类里重写一次就行了 - 接口与接口之间的关系
继承关系,可以单继承,也可以多继承。
如果实现类实现了子接口,那么就需要重写所有的抽象方法
//如果实现类实现了子接口,那么就需要重写所有的抽象方法
//接口1
public interface Inter1{public abstract void method1();
}
//接口2
public interface Inter2{public abstract void method2();
}
//接口3
public interface Inter3 extends Inter1,Inter2{public abstract void method3();
}
//实现类
public class InterImpl implements Inter3{@Overridepublic void method1(){}@Overridepublic void method2(){}@Overridepublic void method3(){}
}
总结:
6.7.2 接口和抽象类案例
流程图思路:
1.
2.最优流程图
//因为直接创建人的对象是没有意义的,所以直接把person创建为抽象类
public abstract class Person {private String name;private int age;public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}
---------------------------------------------------
package com.inherit4.study;public abstract class athletes extends Person{public athletes() {}public athletes(String name, int age) {super(name, age);}public abstract void study();
}
---------------------------------------------------
package com.inherit4.study;public abstract class instructor extends Person{public instructor() {}public instructor(String name, int age) {super(name, age);}public abstract void teach();
}
---------------------------------------------------
package com.inherit4.study;public interface English {public abstract void eng();
}
---------------------------------------------------
package com.inherit4.study;public class ppathletes extends athletes implements English{public ppathletes() {}public ppathletes(String name, int age) {super(name, age);}@Overridepublic void eng() {System.out.println("说英语");}@Overridepublic void study() {System.out.println("学打乒乓球");}
}
---------------------------------------------------
package com.inherit4.study;public class bkathletes extends athletes{public bkathletes() {}public bkathletes(String name, int age) {super(name, age);}@Overridepublic void study() {System.out.println("学打篮球");}
}
---------------------------------------------------
package com.inherit4.study;public class ppInstuctor extends instructor implements English{public ppInstuctor() {}public ppInstuctor(String name, int age) {super(name, age);}@Overridepublic void eng() {System.out.println("说英语");}@Overridepublic void teach() {System.out.println("教打乒乓球");}
}
---------------------------------------------------
package com.inherit4.study;public class bkInstucttor extends instructor{public bkInstucttor() {}public bkInstucttor(String name, int age) {super(name, age);}@Overridepublic void teach() {System.out.println("教打篮球");}
}
---------------------------------------------------
package com.inherit4.study;public class test {public static void main(String[] args) {ppathletes pa=new ppathletes("zhangsan",18);System.out.println(pa.getName()+" "+pa.getAge());pa.eng();pa.study();bkathletes ba=new bkathletes("zhangsi",19);System.out.println(ba.getName()+" "+ba.getAge());ba.study();ppInstuctor pi=new ppInstuctor("lisi",30);System.out.println(pi.getName()+" "+pi.getAge());pi.eng();pi.teach();bkInstucttor bi=new bkInstucttor("zhangliu",36);System.out.println(bi.getName()+" "+bi.getAge());bi.teach();}
}
6.7.3 接口的新增方法
jdk7以前,接口中只能定义抽象方法
jdk8以后,接口中可以定义有方法体的方法(默认,静态)
jdk9以后,接口中可以定义私有方法
即jdk8之后,接口里的方法可以有方法体了
我又想加新的规则;又想让他们的代码不报错怎么办呢?
jdk8以后接口中新增的默认方法
允许在接口中定义默认方法,需要使用关键字default
修饰
作用:解决接口升级的问题
接口默认方法的定义格式:
public default 返回值类型 方法名(参数列表){方法体}
例如:
public default void show(){}
接口中默认方法的注意事项:
- 接口中的默认方法不是抽象方法,所以不强制重写。如果被重写,重写时去掉default 关键字。
- public可以省略,default不能省略
- 如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写。
接口A:
public interface InterA {public abstract void method();public default void show(){System.out.println("InterA接口中的默认方法----show");}
}接口B:
public interface InterB {public default void show(){System.out.println("InterB接口中的默认方法----show");}
}InterImpl:
public class InterImpl implements InterA,InterB{@Overridepublic void method() {}@Overridepublic void show() {InterA.super.show();}
}测试类:
public class Test {public static void main(String[] args) {InterImpl ii = new InterImpl();ii.show();}
}
jdk8以后接口中新增的静态方法
jdk8以后接口中新增的方法(静态方法)
静态方法不能重写。
允许在接口中定义静态方法,需要使用关键字static
修饰
接口静态方法的定义格式:
public static 返回值类型 方法名(参数列表){方法体}
例如
public static void show(){}
接口中静态方法的注意事项:
- 接口中的静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
- public可以省略,static不能省略
重写的概念:
jdk9新增的私有方法
为什么在接口中增加私有方法?
对于一些重复代码,是对单独一个接口中其他方法去服务的,不想被外类去访问,因为外类访问是没有意义的,因此在接口中出现了私有方法
接口中私有方法的定义格式:
格式1:private 返回值类型 方法名(参数列表){}
(不加default关键字,给默认方法服务,即默认方法中的重复代码)
例如:
private void show(){}
格式2:private static 返回值类型 方法名(参数列表){}
(给静态方法服务,即静态方法中的重复代码)
例如:
private static void method(){}
小结:
6.7.4 接口应用
- 把多个类都有可能用到的规则定义成接口,对实现类来讲,想要要实现类拥有什么样的功能,就实现对应的接口就行了。
即接口代表规则,是行为的抽象。想要让哪个类拥有一个行为,就让这个类实现对应的接口就行了 - 当一个方法的参数是接口时,可以传递接口所有实现类的对象,这种方式称之为接口多态。
小结:
6.7.5 适配器设计模型
设计模式:
设计模式是一套被反复利用,多数人知晓的,经过分类编目的,代码设计经验的总结。使用设计模式是为了可重用代码,让代码更容易被他人理解,保证代码可靠性,程序的重用性。
简单理解:设计模式就是各种套路
适配器设计模式:
- 解决接口与接口实现类之间的矛盾问题
就是在接口和实现类中间加上一个单独的类,这个类把接口里的所有方法重写(空着),然后,实现类使用时只需要重写需要的方法就行了
注意,中间类的名字是XXXAdapder
接口:
中间类:
实现类:继承中间的适配器,不让外界创建它的对象
总结:
6.8 初始内部类
类的五大成员:
属性,方法,构造方法,代码块,内部类
内部类就是在一个类里再定义的类
例如:
public class Person{public class Student{}
}
为什么要学习内部类?
代码实现:
内部类的分类
分为:
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
前三种了解一下哎,写代码时能看懂,会用就行,最后一种匿名内部类需要掌握
person类里的student就是内部类,person就是外部类
跟这两个类无关的其他所有类就是外部其他类
- 定义内部类的规则: 内部类表示的事物是外部类的一部分 内部类单独出现没有任何意义
- 内部类的访问特点: 内部类可以直接访问外部类的成员,包括私有的 外部类要访问内部类的成员,必须在外部类里创建对象
案例:
总结:
6.8.1 成员内部类
写在成员位置的内部类就是成员内部类
public class Car {private String carName;private int carAge;private String carColor;eng neng=new eng();public void show2(){System.out.println(neng.engAge+" "+neng.engName+" "+neng.engColor);}class eng{//这里就是成员内部类String engName;int engAge;String engColor;public void show1(){System.out.println(carName+" "+carAge+" "+carColor);}}
}
- 成员内部类代码的书写
1.写在成员位置的,属于外部类的成员,有着成员的性质
2.成员内部类可以被一些修饰符所修饰,比如:private,默认,protected,public,static(用static修饰的内部类就不是成员内部类了,是静态内部类)
3.成员内部类里可以定义静态变量(jdk16以后)
成员内部类的创建
- 方式1:(private修饰时会使用)
在外部类中编写方法,对外提供内部类的对象,可以用Object创建一个先对象来接收内部类对象的返回值,也可以直接使用
注意版本要匹配:
方式1的例子:
public class Outer {private String name;private class Inner{}public Inner getInner(){//创建方法return new Inner();}
}
Outer o=new Outer();
o.getInner();//调用方法
- 方式2: 直接创建格式:外部类名.内部类名 对象名=外部类对象(new 对象).内部类对象(new 对象);
//这里相当于内部类是外部类的成员,创建外部类对象后调用
Outer.Inner duixiang= new Outer().new Inner();
//这里Outer是外部类名,Inner是内部类名
成员内部类获取外部类的成员变量(使用Outer.this.变量,Outer是外部类名)
练习:
内存图解析:
Outer类:
public class Outer {private int a =10;class Inner{private int a =20;public void show(){int a = 30;System.out.println(Outer.this.a);System.out.println(this.a);System.out.println(a);}}
}测试类:
public class Test {public static void main(String[] args) {//创建内部类的对象,并调用show方法Outer.Inner oi = new Outer().new Inner();oi.show();}
}
小结:
6.8.2 静态内部类
例子:
public class Outer {int a=10;static String name="111";//静态内部类static class Inner{public void show1(){Outer oi=new Outer();sout(oi.a);//外部类的非静态对象需要创建对象才能访问sout(name);//外部类的静态变量可以直接访问}public static void show2(){Outer oi=new Outer();sout(oi.a);//外部类的非静态对象需要创建对象才能访问sout(name);//外部类的静态变量可以直接访问} }
}
- 创建静态内部类的语法:
外部类名.内部类名 对象名=new 外部类名.内部类名();
例如:Outer.Inner oi=new Outer.Inner();
(这里new的是Inner) - 用静态内部类对象调用静态内部类中的非静态方法:
先创建对象,用对象调用 - 调用静态内部类中的静态方法:
直接调用:Outer.Inner.方法名()
案例:
public class Outer {//静态内部类static class Inner{public void show1(){sout(非静态的方法被调用了);}public static void show2(){sout(静态的方法被调用了);} }
}
//调用
//调用静态内部类里的非静态的方法,需要先创建一个静态内部类对象,然后用对象调用
Outer.Inner oi=new Outer.Inner();
oi.show1();
//调用静态内部类里的静态的方法,可以直接通过 外部类.内部类.方法名() 调用
Outer.Inner.show2();
小结:
6.8.3 局部内部类
案例:
Outer类:
public class Outer {int b=20;public void show(){int a=10;//局部内部类class Inner{String name;int age;public void method1(){System.out.println(a);System.out.println(b);System.out.println("局部内部类中的method1方法");}public static void method2(){System.out.println("局部内部类中的method2静态方法");}}//创建局部内部类的对象Inner i = new Inner();System.out.println(i.name);//nullSystem.out.println(i.age);//0i.method1();Inner.method2();}
}测试类:
public class Test {public static void main(String[] args) {Outer o = new Outer();o.show();}
}
6.8.4 匿名内部类
匿名内部类的本质就是隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置
匿名内部类有三个特点:
1.实现或继承关系
2.方法的重写
3.创建对象
匿名内部类的语法:
new 类名或接口名(){重写方法();//类或接口的抽象方法的重写
};
//这一段代码的返回值是一个对象,可以被对象变量接收
例如:
new Inter(){public void show(){}
};
即:
new Swim(){//这里的new创建的是后面没有名字的类的对象@Overridepublic void swim(){sout("重写的游泳方法");}
};
/*这一部分从语法上来解释,应该叫做匿名内部类的对象
new Swim(){@Overridepublic void swim(){sout("重写的游泳方法");}
};
*/
/*这一部分才是没有名字类的主体,即匿名内部类,实现了Swim这个接口
{@Overridepublic void swim(){sout("重写的游泳方法");}
};*/
以上代码有三个特点
- 1.实现关系
- 2.方法的重写
- 3.创建对象
同理,当Swim换成一个类名时,特点就变为了
1.继承关系
2.方法的重写
3.创建对象
此时匿名内部类的主题就是父类的子类
new Fulei(){//这里的new创建的是后面没有名字的类的对象@Overridepublic void show(){sout("重写的show方法");}
};
/*这一部分从语法上来解释,应该叫做匿名内部类的对象
new Fulei(){@Overridepublic void show(){sout("重写的show方法");}
};
*/
/*这一部分才是没有名字类的主体,即匿名内部类,继承了Fulei的子类
{@Overridepublic void show(){sout("重写的show方法");}
};*/
应用场景
可以作为方法的实参,不用再写格外的类
比如:
//Animal类(父类)
public abstract class Animal{public void eat(){sout("吃东西")}
}
//Dog类(子类)
public class Dog extends Animal{@Overridepublic void eat(){sout("狗吃骨头")}
}
//测试类
psvm(String[] args){//以前调用method方法Dog d=new Dog();method(d);//使用匿名内部类调用method方法method(new Animal(){@Overridepublic void eat(){sout("狗吃骨头")}}
)
/*
new Animal(){@Overridepublic void eat(){sout("狗吃骨头")}}这个整体就相当于:Animal a=子类对象 ,即多态
*/public static void method(Animal a){a.eat();}
}
拓展:
可以直接用语法的形式调用对象
同理
new Fulei(){//这里的new创建的是后面没有名字的类的对象@Overridepublic void show(){sout("重写的show方法");}
}.show();//所以可以调用自己里面的方法
小结:
相关文章:
小黑子—Java从入门到入土过程:第六章
Java零基础入门6.0Java系列第六章1. 面向对象综合练习1.1 文字版格斗游戏参数占位,格式化输出回顾关于printf和print和println的区别1.2 对象数组练习1.2.1 练习一1.2.2 练习二1.2.3 练习三1.2.4 练习四1.3 键盘录入回顾1.4 复杂对象数组练习1.4.1 复杂练习一1.4.2 …...
python实战应用讲解-【numpy数组篇】常用函数(二)(附python示例代码)
目录 Python numpy.flipud() Python numpy.insert() Python numpy.ravel() Python numpy.shapes() Python numpy.roll() Python numpy.rot90() Python numpy.append() Python numpy.flipud() Python numpy.flipud()函数将数组(每列中的项)按上下方向翻转,但保留形状。…...
windows10 java 创建合约
a. 安装Nodejs 主要是方便使用npm 命令 并配置环境变量 b.使用 npm 可以便捷地安装Solidity编译器solcjs npm install -g solc c.找个目录 创建一个solidity文件 如 // SPDX-License-Identifier: GPL-3.0pragma solidity >0.8.2 <0.9.0;/*** title Storage* dev Store…...
阿里巴巴获得商品详情 API调用示例
为了进行此平台API的调用,首先我们需要做下面几件事情。 1、 获取一个KEY。 2、 参考API文档里的接入方式和示例。 3、查看测试工具是否有需要的接口,响应实例的返回字段是否符合参数要求。 4、利用平台的文档中心和API测试工具,对接口进…...
企业工程管理系统源码-数字化可视化项目管理平台
工程项目各模块及其功能点清单 一、系统管理 1、数据字典:实现对数据字典标签的增删改查操作 2、编码管理:实现对系统编码的增删改查操作 3、用户管理:管理和查看用户角色 4、菜单管理:实现对系统菜单的增删改查操…...
【C语言】一文带你简单了解C语言
这里写目录标题)引言C语言概述基础语法数据类型运算符循环语句分支语句函数数组指针文件操作内存管理高级特性结构体枚举类型联合体预处理器应用场景操作系统编译器游戏开发嵌入式系统引言 C语言是一种通用的计算机编程语言,具有高效、灵活、可移植等特点…...
LeetCode 589 LeetCode590 N叉树的前序遍历和后序遍历
题目: N叉树的前序遍历:给定一个 n 叉树的根节点 root ,返回 其节点值的 前序遍历 。n 叉树 在输入中按层序遍历进行序列化表示,每组子节点由空值 null 分隔。 示例 1: 输入:root [1,null,3,2,4,null,5,…...
为什么CAD多段线没有面积属性或数值不对?快看过来!
有些设计师小伙伴在CAD制图过程中,会遇到这样的一个问题:在CAD图纸中直接选取线条后用工具标出来的面积是实际面积的两倍,而且用CAD面积查询命令直接选择对象查不出面积,这是为什么呢?本文就和小编来给大家分享一下CAD…...
WRF后处理:使用ncl脚本批量提取wrfout变量并输出/Shell 入门:Shell进入不同文件夹执行脚本
目录背景思路NCL提取wrfout特定变量Shell批量执行背景 在之前的博客WRF后处理总结我提到过将NCL与python结合进行后处理的问题,即,使用NCL进行wrfout变量的提取、计算、输出,再用已有python脚本绘图,这样可以极大节省时间。 对于…...
Consul在Windows系统下的安装与启动
1、Consul的简介 Consul 是由 HashiCorp 公司推出的一款开源工具,用于实现分布式系统的服务发现与服务配置。它内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key-Value 存储、多数据中心方案。 Consul 使用 GO 语言编写,因此天然具有可移…...
2022国赛16:神州路由器交换机BGP配置实例1
实验拓扑图 一、基本配置: R1配置: Router>ena Router#conf Router_config#host R1 R1_config#int g0/0 R1_config_g0/0#ip add 202.11.1.1 255.255.255.252 R1_config_g0/0#int l0 R1_config_l0#ip add 1.1.1.1 255.255.255.255 R1_confi...
PaddlePaddle NLP学习笔记1 词向量
文章目录1.语言模型 Language Model1.1 语言模型是什么1.2 语言模型计算什么1.3 n-gram Language Model2.神经网络语言模型NNLM2.1 N-gram模型的问题3. 词向量3.1 词向量(word Embedding)word2vec 词向量训练算法3.2 如何把词转换为词向量?3.3如何让向量具有语义信息…...
无重复全排列 [2*+]
目录 无重复全排列 [2*+] 程序设计 程序分析 无重复全排列 [2*+] 输出N个数的无重复全排列 Input 输入一个数值N 1<=N=50 Output 输出N个数的无重复全排列,每个数之间用空格隔开 最后一行输出无重复全排列的个数。 Sample Input 3 Sample Output 1 2...
【血泪建议】软件测试岗位现状,可惜之前没人告诉我,肠子都晦青了....
谈到现状,国内的软件测试行情目前呈现了两极分化的极端情况。 一个是早期的手工测试人员吐槽工作不好做,即使有工作也是外包,而且薪资太低;一方面是很多互联网企业感叹自动化测试人才难找,有技术的自动化测试工程师&a…...
Elastic(ELK) Stack 架构师成长路径
Elastic Stack(ELK Stack)是一个开源的日志分析平台,由 Elasticsearch、Logstash 和 Kibana 三个组件组成,主要用于数据搜索、分析和可视化。要成为一名 ELK Stack 架构师,需要遵循一定的成长路径,以便逐步…...
Netty的高性能体现在哪些方面
文章目录Netty的高性能体现在哪些方面1. 非阻塞I/O2. 零拷贝3. 内存池4. 线程模型Netty的高性能体现在哪些方面 Netty是一个高性能、异步事件驱动的网络应用程序框架,它具有出色的稳定性和灵活性。在现代的分布式系统和互联网应用中,Netty已经成为构建高…...
CompletableFuture详解
1、概述 咱们都知道可以通过继承Thread类或者实现Runnable接口两种方式实现多线程。但是有时候我们希望得到多线程异步任务执行后的结果,也就是异步任务执行后有返回值,Thread和Runnable是不能实现的。当我们需要返回值的时候怎么办呢? Java…...
(学习日记)2023.3.10
写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈。 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录&a…...
【图像分割】Meta分割一切(SAM)模型环境配置和使用教程
注意:python>3.8, pytorch>1.7,torchvision>0.8 Feel free to ask any question. 遇到问题欢迎评论区讨论. 官方教程: https://github.com/facebookresearch/segment-anything 1 环境配置 1.1 安装主要库: (1&…...
AJ入门路线
一.AspectJ 入门 概述安装示例代码切入点表达式thisJoinPointStaticPart 和 thisJoinPoint与Spring 切面写法的对比总结 初步了解了aspectJ的使用,我们可以了解以下几点: 1)aspectJ的使用是在编译期,通过特殊的编译器可以在不改变…...
多商户商城小程序源码开发需具备哪些功能?
随着电商的进一步发展,传统企业为了更好的占领市场也纷纷向电商市场迈进,着手打造属于自己的商城系统。多商户商城系统是一种多商户、多商品、多支付的电子商务平台,功能丰富,涵盖多个行业,能够满足多种商家和用户的需…...
【动态规划模板】最长公共|上升子序列问题
最长公共子序列🍉 给定两个长度分别为N和M的字符串A和B,求既是A的子序列又是B的子序列的字符串长度最长是多少。 输入格式 第一行包含两个整数 N 和 M。 第二行包含一个长度为N的字符串,表示字符串A。 第三行包含一个长度为M的字符串&am…...
Android系统启动流程--zygote进程的启动流程
在上一篇init进程启动流程中已经提到,在init中会解析一个init.rc文件,解析后会执行其中的命令来启动zygote进程、serviceManager进程等,下面我们来看一下: //文件路径:system/core/init/init.cppstatic void LoadBoot…...
C++程序设计——异常
一、C异常概念 异常处理是一种处理错误的方式,当一个函数发现自己无法处理的错误时,就可以抛出异常,让函数的直接或间接的调用者处理这个错误。 (1)throw:当问题出现时,程序会通过throw关键字抛…...
2022年第十三届蓝桥杯web开发—东奥大抽奖【题目、附官方解答】
冬奥大抽奖 介绍 蓝桥云课庆冬奥需要举行一次抽奖活动,我们一起做一个页面提供给云课冬奥抽奖活动使用。 准备 开始答题前,需要先打开本题的项目代码文件夹,目录结构如下: ├── css │ └── style.css ├── effect.g…...
一份两年前一个月的工作经历没写在简历上,背调前主动坦白,却被背调公司亮了红灯,到手的offer没了!...
只因为简历上漏写了一份一个月的工作,就被亮了背调红灯,这公平吗?一位网友就被狠狠坑了一把,来看下他的遭遇:他有一份两年前、时长一个月的工作经历没写在简历上,背调前主动和背调公司还有招聘方hr都说了这…...
C++游戏分析与破解方法介绍
1、C游戏简介 目前手机游戏直接用C开发的已经不多,使用C开发的多是早期的基于cocos2dx的游戏,因此我们这里就以cocos2d-x为例讲解C游戏的分析与破解方法。 Cocos2d-x是一个移动端游戏开发框架,可以使用C或者lua进行开发,也可以混…...
食堂总是拥挤不堪?解决用餐拥挤,教你一招
随着近几年科技的快速发展,行业里出现了很多新的名词,比如智慧社区、智慧旅游、智慧建筑,那么智慧食堂是什么呢?它又是如何实现全自助、全智能消费? 在先进的智能技术以及市场需求带动下,智慧食堂经历了由传…...
ubuntu系统安装时 MBR和GPT的区别
主引导记录(Master Boot Record , MBR)是指一个存储设备的开头 512 字节。它包含操作系统的引导器和存储设备的分区表。 全局唯一标识分区表(GUID Partition Table,缩写:GPT)是一个实体硬盘…...
我在windows10下,使用msys64 mingw64终端
系列文章目录 文章目录系列文章目录前言一、MSYS2是什么?前言 msys2官网 MSYS2 (Minimal SYStem 2) 是一个MSYS的独立改写版本,主要用于 shell 命令行开发环境。 同时它也是一个在Cygwin (POSIX 兼容性层)…...
网站死链如何修改/网站关键词如何优化
可以看访问你网站的人都分布在那些省市! 老外做过一个全球了。 我只能做一个全国的了。 呵呵。 现在只是做演示。 而且我的事虚拟主机。 暂时不能公开使用。 只是让大家看一下。 呵呵。 转载于:https://www.cnblogs.com/MysticBoy/archive/2008/12/13/1354464.html…...
做ppt的背景图片网站/网络营销案例100例
二叉树的镜像 class Solution { public:TreeNode* mirrorTree(TreeNode* root) {if(root nullptr) return nullptr;swap(root->left,root->right);mirrorTree(root->left);mirrorTree(root->right);return root;} };...
成都品牌包装设计/企业网站优化哪家好
2019独角兽企业重金招聘Python工程师标准>>> 方法1 - 使用Eclipse Eclipse里新建一个服务器: 服务器类型选择SAP Cloud Platform: 点Finish,成功创建了一个Server: Eclipse里选择要部署的项目,右键->…...
ps制作网站首页面教程/如何优化网站推广
之前谈到免货运,真的很难,你想如果是你在网上购买食品,你一般会购买多少?有的人会说,我会很多,但是你在看看食品的价格是多少,也许你购买了一大袋食品价格也许不会超过100块,但是从重…...
做网站配置好了找不到服务器/长沙seo网络营销推广
简单是可靠的前提条件真正程序员从来不写代码的注释,如果代码非常难写,那么同样代码的注释也会非常难懂 看看当前计算机程序糟糕的事态,软件开发明显一直是一门妖术,其仍然不能被称为一个工程学。–比尔.克林顿 美国前总统...
做网站上传的图片大小/百度关键词查询工具
本发明涉及电机控制领域,尤其涉及一种电机h桥制动电路。背景技术:电动立柱的电机控制一般有两种,一种是h桥的四个开关管控制一个电机的正反转和转速;另一种是通过两个继电器控制电机的正反转,一个开关管控制电机的转速…...