拓展
一、常量
之前学过“变量” , 今天了解常量!
常量:内容不能修改的量!
public static void main(String[] args) { int r = 4; //常量的命名规则:常量名 应该全大写 final double PI = 3.14; System.out.println(PI * Math.pow(r,2)); }
常量使用final 来进行进行修饰!
final 只能用来修饰常量么?答案不是,final除了可以修饰常量,还可以修饰方法,以及修饰类!
//final修饰的类,是最终类,太监类 //不能被继承的类 public final class Human { //常量:染色体的数量 public static final int CHROMOSOME_NUMBER = 46; //final 修饰方法,表示:该方法不能被子类重写 //因为它是最终方式 public final void study(){ System.out.println("你好!"); } }
eg:String 其它的包装类 Integer Long Double Float Short Byte Character Boolean
二、ArrayList
ArrayList 是个List集合,作用:存储大量的相同/相似的数据!
底层:数组
特点:
1.有序,添加的顺序&输出的顺序是一样的
2.可以存放重复数据
public class MainEnter { public static void main(String[] args) { List<String> datas = new ArrayList<>(); datas.add("张三"); datas.add("李四"); datas.add("王五"); datas.add("张三"); for (String data : datas) { System.out.println(data); } } }
三、HashSet
public class MainEnter { public static void main(String[] args) { //需求:不希望有重复数据 Set<String> datas = new HashSet<>(); datas.add("张三"); datas.add("李四"); datas.add("王五"); datas.add("张三"); for (String data : datas) { System.out.println(data); } } }
特点:
1.无序
2.去重
四、补充
1.双层循环中,一个变量定义在外层,内层,夹层,有什么不同?
2.java中有没有goto关键字?有没有什么语法可以变通出goto流程?
-循环标签
goto 在c语言中,用来跳转指针使用!Java中确实存在这个关键字,但是没有用!
3.递归,可用斐波那契数列和阶乘举例.既能递归又能循环,如何选择?什么场合只能递归?
遍历:使用循环,将集合或数组中的每个元素 都取出来!
递归:方法自己不断的调用自己!
需求:
public class MainEnter { public static void main(String[] args) { login(); } public static void login(){ System.out.println("输入你的登录名:"); System.out.println("输入你的密码:"); login(); } }
当递归使用不当的情况,可能出现:栈溢出的错误
解决方案:
public class MainEnter { public static String account = "admin"; public static String pwd = "123456"; public static void main(String[] args) { if(login()){ System.out.println("登录成功,系统即将跳转首页!"); } } public static boolean login(){ boolean flag = false; System.out.println("输入你的登录名:"); String loginName = new Scanner(System.in).next(); System.out.println("输入你的密码:"); String password = new Scanner(System.in).next(); if(loginName.equals(account) && password.equals(pwd)){ flag = true; }else{ flag = login(); } return flag; } }
五、JVM在运行期间的内存分配
JVM :Java虚拟机!
作用:为Java程序提供一个运行的环境!
特点:不同的操作系统,具有不同的JVM环境!才能做到“跨平台”
栈:是一种上开下闭的数据结构,空间中主要存储:方法,已经方法中定义的变量
堆:放置new出来的对象,字符串常量池
程序计数器:记录代码的执行顺序
本地方法栈:存储跟底层操作系统有关的方法,通常这种方法都是C语言编写的
元空间:在JDK1.7时,也是存放在JVM内部的。但是在JDK1.8时,已经存放在物理内存中,
public class MainEnter { public static void main(String[] args) { int a = 10; int b = 12; String str = new String("张三"); Student stu = new Student(1,"李四"); } }
Java有2种数据类型:基本数据类型,引用数据类型
基本数据类型:变量 & 值 位于同一个地方!
引用数据类型:变量中存储的是 对象的内存地址,而不是具体的内容!
六、Java的值传递
方法中传入对象,并且针对对象的内容进行修改,请问这个是值传递还是引用传递?
public static void main(String[] args) { Student stu = new Student(1,"张三"); modifyStudent(stu); System.out.println(stu); } public static void modifyStudent(Student student){ student.setName("李四"); }
基本数据类型,在传递时,复制的是变量的值!
引用数据类型,在传递时,复制的也是变量的值!只不过这个值,是地址值而已!
七.关于static,静态成员与实例成员的区别.
-静态成员属于类,多个对象间共享.
-非静态成员属于对象
静态的成员,因为它是类的东西,所以调用方式:类名.属性 类名.方法()非静态的成员,因为它是对象的东西,所以调用的方式:对象.get属性() 对象.方法()
静态的方法,不能直接调用 非静态的属性/方法!
非静态的方法,可以直接调用 静态的属性/方法!
什么叫多态.
多态:相同的行为,不同的实现!
具体的体现方式:
-父类的引用指向子类的对象
-接口的引用指向实现类的对象
-多态时,方法名列表看父类,执行过程看子类.
-常规类->抽象类->接口 : 三者从大范畴上都属于类,三者的演变是一个逐步变得残缺的过程.
重载与重写.
-同一个类里,两个方法,同名不同参,叫作重载.
-注意同名又同参,但返回不同,不能构成重载.
-两个类里,子类重写父类方法,实现类重写接口方法.
八.谈谈堆,栈,常量池,以及无限递归为什么发生栈溢出?常量池的去重特性是什么?如何证明?
-基础型数据存栈
-对象型数据,引用部分存栈,对象内容部分存堆.
-字符串可以存常量池,可以存堆.
-堆空间受垃圾回收机制管理,不易溢出.
public class MainEnter { public static void main(String[] args) { String a = "张三"; String b = "李四"; String c= "张三"; //常量池:张三,李四 } } //JVM在加载时,就会针对 字符串常量进行去重操作! //校验方式,使用JAVA/bin目录下的javap工具,具体的命令:javap -v 类名.class
九.List与Set的区别,Arraylist与LinkedList的区别,HashSet与TreeSet的区别.
-List有序, 不去重
-Set无序, 去重
(HashSet内在顺序不可自定义,TreeSet内在顺序可以自定义,通过传入比较器.)
-少数非主流list或set不符合以上规则.
-ArrayList底层是数组,读取快,增删慢.LinkedList底层是双向链表,读取慢,增删快.
十.==/equals()/hashcode()区别?String的equals()与hashcode()为什么针对内容?
-默认对象中,三者均针对地址.
-==不可重写,后二者可重写,重写后可以针对地址,也可以针对内容.
-String中的equals()/hashcode()都是重写过的,所以针对内容.
-对于一个自定义类,我们一旦重写了equals(),就要同步重写hashcode(),这个规范是用来满足set类集合判重的.
public class Suspect { private int id; private String name; private String idcard; private String dna; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Suspect suspect = (Suspect) o; return Objects.equals(dna, suspect.dna); } @Override public int hashCode() { return Objects.hash(dna); } //getter() & setter() //toString() } public class MainEnter { public static void main(String[] args) { //分析DNA的结果是 Suspect suspect = new Suspect("张三","10086","111"); //现在有3个嫌疑人 Suspect a = new Suspect("李四","10001","222"); Suspect b = new Suspect("王五","345345","111"); Suspect c = new Suspect("赵六","12315","333"); //找到罪犯 System.out.println(suspect.equals(a)); System.out.println(suspect.equals(b)); System.out.println(suspect.equals(c)); } }
为什么重写了equals() ,还要重写hashcode() ?
System.out.println("Aa".hashCode()); //hashcode = 2112 System.out.println("BB".hashCode()); //hashcode = 2112 在Java中,可能出现: 不同的对象,可能具有相同的Hash值! 相同的对象,他们的Hash值一定相同!
所以,HashSet 去重的原理是:先比较内存地址的值,然后再比较内容的值!
所以:
public class MainEnter { public static void main(String[] args) { Suspect suspect = new Suspect("张三","123","111"); Suspect a = new Suspect("李四","234","222"); Suspect b = new Suspect("张三","123","111"); Suspect c = new Suspect("赵六,"456","333"); //这里要想实现:根据dna去重,需要在Suspect 根据dna重写equals() & hashcode() Set<Suspect> sus = new HashSet<>(); sus.add(suspect); sus.add(a); sus.add(b); sus.add(c); System.out.println(sus.size()); for (Suspect sus1 : sus) { System.out.println(sus1); } } }
UserInfo 属性:id(int),name(String) ,age(int) ,idcard(String) , blood(String)
要求:
1、所有的属性私有化,提供getter & setter ,toString()
2、在MainEnter的main() 中,创建2个UserInfo ,只要idcard & blood一致,就认为这2个对象,是同一个对象!
十一、HashSet & Treeset的区别
HashSet & Treeset 都是Set集合的实现类,都可以实现内容的去重!
HashSet 去重的原理:先比较hashcode的值,想通的hashcode,然后再调用equals() 方法完成去重!
HashSet 是无序的,内部可能有顺序!
TreeSet 打印顺序&存放的顺序仍旧不同,但是内部的元素是进行排序的!
TreeSet 根据比较器来完成去重!当比较器的值=0,表示两个对象是同一个对象!
public class MainEnter { public static void main(String[] args) { Set<Integer> datas = new TreeSet<>(); datas.add(11); datas.add(9); datas.add(5); datas.add(22); for (Integer data : datas) { System.out.println(data); } } }
如何实现排序的呢?依靠:Comparator 比较器
两种比较器Comparator & Comparable
public class Student implements Comparable<Student>{ @Override public int compareTo(Student o) { return o.getAge() - this.getAge(); } }
但是:程序员为了减少代码的 耦合度,于是:喜欢使用Comparator
十二、匿名内部类
内部类:定义在类内部的类!不是问你:累不累?
匿名内部类:一个没有名字的内部类!
public class MainEnter { public static void main(String[] args) { //使用匿名内部类,定义比较器 Comparator<Student> comparator = new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o2.getAge() - o1.getAge(); } }; List<Student> stus = new ArrayList<>(); stus.add(new Student("张三",22)); stus.add(new Student("张三",18)); stus.add(new Student("张三",26)); stus.add(new Student("张三",15)); Collections.sort(stus,comparator); //需求:按照年龄 升序排列 for (Student student : stus) { System.out.println(student); } } }
public class MainEnter { public static void main(String[] args) { //卖手机 Goods g1 = new Goods("iphone20",20000,200); Goods g2 = new Goods("huaweimeta60",12000,120); Goods g3 = new Goods("xiaomi14plus",22000,200); List<Goods> goods = new ArrayList<>(); //将3台设备,添加到goods集合中去 Collections.addAll(goods,g1,g2,g3); //先按照销量排序,再按照价格排序 Collections.sort(goods, new Comparator<Goods>() { @Override public int compare(Goods o1, Goods o2) { int i = o2.getSellNumber() - o1.getSellNumber(); if(i == 0){//销量一样,再按照价格升序 return o1.getPrice() - o2.getPrice(); }else{ return i; } } }); //打印输出:排序的结果 for (Goods good : goods) { System.out.println(good); } } }