大家好,欢迎来到IT知识分享网。
2.28
五分钟爬虫
蚂蚁学
fstring
简单使用
f-string用大括号 {} 表示被替换字段,其中直接填入替换内容:
>>> name = 'Eric' >>> f'Hello, my name is {name}' 'Hello, my name is Eric'
学习的excel的网站 数据导入——》数据——》自网站——》属性——》导入
headfirstjava
有成千上百个文件怎么提交?
把所有文件包装进依据pkzip 格式来存档的Java Archive-.jar 文件。
在jar文件中可以引入一个简单的文字格式的文字文件,为manifest ,里面有定义出jar中的哪一个文件带有启动应用程序的main()方法。
创建数组
Dog b = new Dog(); //普通对象创建 Dog[] pets; //声明数组变量,数组名为pets,因为数组用来引用Dog 类的对象所以用 Dog[] 创建 pets = new Dog[7] //创建大小为7的数组,并赋给pets 变量 //注意,前两句可用在一起: Dog [] pets = new Dog[7]; pets[0] = new Dog(); //创建对象并赋给数组元素 //注意数组中只有Dog 的引用变量
注解:上两句是创建一个长度为7的数组(这个数组用来存放Dog 类的实例 的引用变量)
然后创建一个Dog 对象,并将此引用变量赋值给这个数组。
//用数组索引就能操作对象 Dog[] myDogs = new Dog[3]; myDogs[0] = new Dog(); myDog[0].name = "Fido"
java是通过值传递的,即通过拷贝传递。
实例变量 一直有默认值 0 或者 0.0 或者 null。而局部变量没有默认值,编译报错。
实例变量 的声明在类里,局部变量的声明在方法里
==和equals
==比较两个主数据类型,判断两个引用是否引用同一对象
equals() 对象是否在意义上相等。
int a = 3; byte b = 3; a==b true //比较字节组合 Foo a = new Foo(); Foo b = new Foo(); Foo c = a; a == b false; a == c true; b == c false; //比较引用类型 是否相等
3.1
headfirstjava
转换整型
Integer.parseInt("3")
ArrayList
类有完整的名称,事实叫做java.util.ArrayList 。ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。ArrayList 继承了 AbstractList ,并实现了 List 接口。
import java.util.* //创建 在堆上 ArrayList<Egg> myList = new ArrayList<Egg>(); //Egg 为类型参数 //加入元素 Egg s = new Egg(); myList.add(s); //加入元素 Egg b = new Egg(); myList.add(b); //查询大小 此时大小为2 int theSize = myList.size(); //修改元素 myList.set(2,<Object>) ; //查询特定元素 boolean isIn = myList.contains(s); //此时返回 true //查询特定位置 int idx = myList.indexOf(b); //判断是否为空 boolean empty = myList.isEmpty(); //删除元素 此时大小为1 myList.remove(s); //参数也可以是索引值
数组和ArrayList 都是对象,保存在堆上。
Collections 类也是一个非常有用的类,位于 java.util 包中,提供的 sort() 方法可以对字符或数字列表进行排序。
import java.util.ArrayList; import java.util.Collections; // 引入 Collections 类 public class RunoobTest {
public static void main(String[] args) {
ArrayList<String> sites = new ArrayList<String>(); sites.add("Taobao"); sites.add("Wiki"); sites.add("Runoob"); sites.add("Weibo"); sites.add("Google"); Collections.sort(sites); // 字母排序 for (String i : sites) {
System.out.println(i); } } }
LinkedList
与 ArrayList 相比,LinkedList 的增加和删除对操作效率更高,而查找和修改的操作效率较低。
以下情况使用 ArrayList :
- 频繁访问列表中的某一个元素。
- 只需要在列表末尾进行添加和删除元素操作。
以下情况使用 LinkedList :
- 你需要通过循环迭代来访问列表中的某些元素。
- 需要频繁的在列表开头、中间、末尾等位置进行添加和删除元素操作。
LinkedList 继承了 AbstractSequentialList 类。
LinkedList 实现了 Queue 接口,可作为队列使用。
LinkedList 实现了 List 接口,可进行列表的相关操作。
LinkedList 实现了 Deque 接口,可作为队列使用。
LinkedList 实现了 Cloneable 接口,可实现克隆。
LinkedList 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。
短运算符和长运算符 && &
短运算符如&& 和 || 如果java虚拟机发现左边算式成立,则不会去管右边的
长运算符如 & 和 | 强制运算两边表达式,这两个运算符来做位运算。
继承
防止子类中出现重复的代码
public class Doctor{
boolean workAtHospital; void treat(){
} } public class Surgeon extends Doctor{
void suregy(){
} }
多重继承在调用方法时会从最底层的找,即子类的子类。
继承的方法可被覆盖,但实例变量不会被覆盖。
super
//公共父类 public class Animal {
private String name; private int id; public Animal(String myName, int myid) {
name = myName; id = myid; } public void eat(){
System.out.println(name+"正在吃"); } public void sleep(){
System.out.println(name+"正在睡"); } public void introduction() {
System.out.println("大家好!我是" + id + "号" + name + "."); } }
public class Penguin extends Animal {
public Penguin(String myName, int myid) {
super(myName, myid); // 注意super 的用法 } }
多态
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child();
Animal myDog = new Dog(); //例子 Animal[] animals = new Animal[5]; animals [0] = new Dog(); animals [1] = new Cat(); animals [2] = new Wolf(); //... 可以放任意对象进去 for (int i = 0; i< animals.length; i++){
animals[i].eat(); animals[i].roam(); }//你可以将数组元素逐个调出来当Animal 来操作
参数和返回类型也可以是多态
class Vet{
public void giveShot(Animal a){
//do a.makeNoise(); } }//参数a 可以是任意animal 的对象 class PetOwner{
public void start(){
Vet v = new Vet(); Dog d = new Dog(); v.giveShot(d); v.giveShot(h);//只要传入的参数是animal类型 } }
覆盖的规则
方法的覆盖不能改变参数,不然就是重载。也不能改变权限,public 和private。
抽象
对类抽象 前面加上abstract。 抽象类不能被new
方法的抽象
public abstract void eat();
注意抽象的方法不能有 { } ,直接结束。
声明抽象的方法,必须把类也抽象。非抽象类不能有抽象方法。
虽然抽象方法没有任何用处,但是放在抽象的父类里,可以定义出子类的协议。好处就是多态。
必须在继承数结构下的第一个具体类必须实现所有抽象方法!
如果下一层还是抽象类,可以也不用实现抽象父类的抽象方法。
Object 对象
//所有类都有的方法 equals(); getClass(); hashCode(); //打出hash代码,一个唯一的id toString(); //有的方法标记为final,不可覆盖
Object 不是抽象类!
任何从ArrayList 中取出的东西会被当作Object 引用类型,不管放进去是什么类型的。
ArrayList<Dog> myDogArrayList = new ArrayList<Dog>(); Dog aDog = new Dog(); myDogArrayList.add(aDog); Dog d = myDogArrayList.get(0); ArrayList<Object> myDogArrayList = new ArrayList<Object>(); Dog aDog = new Dog(); myDogArrayList.add(aDog); Dog d = myDogArrayList.get(0); //此句无法通过编译!,因为取出来的已经是Object了
取到的是Dog实例的Object引用!
编译器是根据引用类型来判断哪些方法可用
HTTP
缺点是:通信使用明文,会被窃听; 不验证对方身份;无法证明报文完整性
HTTPS 多了一个SSL (安全套阶层)或TSL(标准安全层)
3.2
headfirsjava
接昨日
Snowboard s = new Snowboard(); Object o = s; //s 能使用Snowboard的方法以及继承下来的Object的方法。而 o 只能用Object的方法。
如何将Object对象转化位原来的?
从Object中拷贝出一个Dog引用。,并赋给Dog引用变量。
Object o = al.get(index); //取出ArrayList的这个引用(是object的) Dog d = (Dog) o; //转换为Dog赋值给Dog 引用变量 d.roam(); // 可以使用Dog的方法
如果不能确定,用instanceof 运算符检查,如果转换类型错了,会遇到ClassCastException异常终止。
if (o instanceof Dog){
Dog d = (Dog) o; }
思考:如果Cat 和 Dog 要带有Pet 的功能,而不让有些动物成为Pet?
方法一:直接加在animals 里,显然不好
方法二:加在animals的抽象类,再具体实现,非宠物也有宠物外观,不行
方法三:直接加进Cat 和Dog 里,不行
方法:创建带有宠物方法 的抽象类,和animal 抽象类并列,多重继承?然而java不支持
接口
interface 关键字
java 的接口好像是100%的纯抽象类(复习:即所有方法都为抽象方法的类)
//定义 public interface Pet{
//interface 代替class public abstract void beFriendly(); public abstract void play(); //接口的方法一定是抽象的!且没有内容! } //实现 public class Dog extends Canine implements Pet{
public void beFriendly(){
...} public void play(){
...} //必须实现方法! } //implement 在某个继承之下
这样,不同的类对象也可以实现相同接口
如Robot 和Animal 平级,则 RobotDog 和 Dog 都可以有Pet这个接口。
当把一个类当作多态类运用时,相同的类型必须来自同一个多态类,而接口则不必要。
public class Dog extends Animal implements Pet, Saveabel, paintable{
...}//可实现多个
调用父类方法 super
super 关键字用来引用父类对象
abstract class Report{
void runReport(){
} void printReport(){
} } class BuzzwordsReport extends Report{
void runReport(){
super.runReport(); //调用父类方法 buzzwordCompliance(); printReport(); } }
堆 栈
对象的生存空间堆 ,方法调用和生存空间栈。
局部变量在栈上,实例变量在堆上。
问题:当一个对象带有另一个引用类型变量呢?
因为java会留下空间给实例变量的值,但是引用变量的值不是对象本身。所以对象带有另一个引用变量,Java只会留下引用量而不是对象本身所用到的空间。
实例变量声明过程:
private Antenna ant; //声明时没有赋值,只会留下变量的空间 //直到引用变量赋值一个新的对象才会在堆上有空间 private Antenna ant = new Antenna();
三步骤:声明、创建、赋值
new Antenna() 看起来像是在调用Antenna() 这个方法,然而是调用Antenna的构造函数。
构造函数
构造函数没有返回类型,且编译器会自动写。 构造函数不会被继承。
public Antenna(){
}
关键特征:它会在对象能够被赋值引用之前就执行。,用于初始化状态。
public class Duck{
public Duck(){
System.out.println("Quack"); } }
public clas Duck{
int size; public Duck(){
size = 21 //默认值 } public Duck(int ducksize){
size = ducksize; } } ------------------------在使用时: Duck d = new Duck(17); Duck d = new Duck(); //不知道size 的情况也有
父类的构造函数
在创建新对象时,所有继承下来的构造函数都会被执行。 称为constructor chaining
执行顺序:栈
对于Object –> Animal –> Dog :
Dog()是最早调用的,但是最晚执行的,构造函数执行顺序:Object –> Animal –> Dog
public class Duck extends Animal{
int size; public Duck(int newSize){
Animal(); //错误! 这不合法! size = newSize; } } //super() 是调用父类构造函数的唯一方法 public class Duck extends Animal{
int size; public Duck(int newSize){
super(); size = newSize;//注意:super必须是第一个语句,如果没写,系统自动加在第一句。 } }
调用父类构造函数会一直上行,直到Object ,然后在依次执行。
系统只会帮忙调用无参数的super()
public abstract class Animal{
private String name; public String getName(){
return name; } public Animal (String theName){
name = theName; } } /*/ public class Dog extends Animal{
public Dog(String name){
super(name); } } // public class MakeDog{
public static void main(String[] args){
Dog h = new Dog("Huhh"); System.out.println(h.getName()); } }
this
使用this() 来从某个构造函数调用同一个类的另一个构造函数。
this() 只能用在构造函数中,且必须是第一行语句。
super() 和 this() 不能兼得。
class Mini extends Car {
Color color; public Mini(){
this(Color.Red); } //无参数的构造函数以默认的颜色调用真正的构造函数 public Mini(Color c){
super("Mini"); color = c; //初始化动作 } //真正的构造函数 public Mini(int size){
this(Color.Red); //有问题 super(size) } }
生命周期
对象的生命周期完全看它的引用。引用在,对象就还在堆上。
局部变量只会生存在声明该变量的方法中。
有时该方法调用别的方法时,局部变量在存在在堆栈上,但是不能使用,区分life 和scope的区别
只有该方法在栈顶时才能使用。
实例变量的寿命和对象相同。
引用变量:当永久性离开它的范围;或者引用到了其他对象上;或者直接将引用设为null
静态
以类的名称调用静态方法 Math.min(88,86);
以引用变量的名称调用非静态的方法 Song t2 = new Song(); t2.play();
Math类无法被初始化,因为它的构造函数为私有的。
有main的类都算有静态方法。
静态的方法不能调用非静态的变量。
public class Duck {
private int size; public static void main(String[] args) {
System.out.println("Size of the duck is "+ size);//报错 } public void setSize(int s){
size = s; } public int getSize(){
return size; } }
Non-static field 'size' cannot be referenced from a static context
静态的方法是无法在特定类的实例情况下执行。因为静态的方法无法通过类的名称来调用,所以静态的方法无法引用该类的任何实例变量。
静态的方法也不能调用非静态的变量。
静态变量的值对所有的实例来说都相同。
静态变量只会在类第一次载入时被初始化:静态变量被同类的所有实例共享的变量。
public class DuckTest {
public static void main(String[] args){
Duck gaga = new Duck(); gaga.setSize(12); System.out.println(gaga.getSize()); System.out.println(gaga.duckNum()); Duck papa = new Duck(); System.out.println(papa.duckNum()); System.out.println(gaga.duckNum()); } }
12 1 2 2
final
静态的final 变量是常数。
public static final double PI = 3.973; //常数变量的名称都应该是大写!
初始化:(注意不初始化就会报错)
public class Foo{
public static final int FOO_X = 25; //注意命名全是大写字母 } //静态初始化程序: public class Bar{
public static final double BAR_SIGN; static{
//这段程序会在类被加载时执行 BAR_SIGN = (double) Math.random(); } }
final 不止用在静态变量上:
final的方法表示不能被覆盖; final的类不能创建它的子类。final
final class Foo{
}
静态的方法可以直接调用而不需要堆上的实例。
静态的方法不能存取非静态的方法。
Java的常量是把变量标记为static 和 final 的 !!!!
final的静态变量值必须在声明或静态初始化程序中赋值
主数据类型的包装
每一个主数据类型都有一个包装用的类,在java.lang 中,不用import。(全改成大写首字母)
Boolean Interger
Character Long
Byte Float
Short Double
//包装类的使用 int i = 288; Integer iWarp = new Integer(i); //解开包装 int unWrapped = iWap.intValue(); //在java 5.0 之前要以对象方式处理主数据就要包装起来
autoboxing
autoaboxing 功能自动包装成对象
public void doNumNewWay() {
ArrayList<Integer> listOfNumers = new ArrayList<Integer>(); listOfNumbers.add(3); //ArrayList 没有add方法,但是编译器会自动包装。 int num = listOfNumbers.get(0); //编译器自动解开对象的包装。 } //注意 ArrayList<int> 无法通过编译,使用时需要注意
使用场所:
//方法的参数 void takeNumber(Integer i){
} //返回值 return x; //x就可以是包装对象 //数值运算 Integer i = new Integer(42); Integer k = i+3;
包装类也有静态方法
//将String 转换为主数据 String s = "2"; int x = Integer.parseInt(s); double d = Double.parseDouble("2132.1"); boolean b = new Boolean("true").booleanValue(); //注意没有parseBoolean()
但是这是错误:
String t = "two"; int y = Integer.parseInt(t); //可以编译,执行出问题
将主类型数据转化为String:
double d = 45.5; String doubleString = ""+d; // + 操作符是java 唯一重载过的操作符 double d = 42.5; String doubleString = Double.toString(d); //Double 类的静态方法。
数字格式化
java.util 的 Formatter 类
public class TestFormats{
public static void main (String[] args){
String s = String.format("%, d",); System.out.println(s); } } //输出 1,000,000,000
3.3
java的格式化输出和c不一样的地方。不在printf里面而是format
//表示日期和时间 String.format("%tc", new Date()); //只有时间 String.format("%tr", new Date()); //周、月、日 Date today = new Date(); String.format("%tA, %tB %td",today,today,today); //特殊符号 < String.format("%tA, %<tB %<td",today); // < 这个符号告诉格式化程序重复利用之前的参数
headfirst Java
时间处理
java.util.Calendar 这个API
取得继承过Calendar的对象
Calendar cal = new Calendar(); //无法通过编译 Calendar cal = Calendar.getInstance(); //要用静态的方法
你无法取得Calendar实例,但可以取得它具体子类的实例,Calendar 是抽象的。但还是能不受限制地调用Calendar的静态方法,因为静态的方法是在类上而不是在某个特定的实例上。
静态方法和非静态方法的区别
Calendar c = Calendar.getInstance(); c.set(2004,1,7,15,40); long day1 = c.getTimeInMillis(); //将时间转化为millisecond表示 day1 += 1000 *60*60; c.setTimeInMillis(day1); //将时间加上一小时 System.out.println("new hour" + c.get(c.HOUR_OF_DAY)); c.add(c.DATE, 35); //加上35天 System.out.println("add 35 days " +c.getTime()); c.roll(c.DATE,35); //滚动35天,只有日期会动,月不会 System.out.println("roll 35 days "+ c。getTime()); c.set(c.DATE, 1); //直接设定DATE的值 System.out.println("set to 1 " +c.getTime());
new hour16 add 35 days Sat Mar 13 16:40:21 CST 2004 roll 35 days Wed Mar 17 16:40:21 CST 2004 set to 1 Mon Mar 01 16:40:21 CST 2004 Process finished with exit code 0
静态import
import static java.lang.System.out; //之后就能用 out.println(); //但是不推荐,会混淆
本章回顾
构造函数不可以标记为静态的 。
构造函数是在静态变量的初始化之后执行的。
如果类标记为final,则它的方法也标记为final (错误)
PCA的数学原理
细节补充
iterator 接口
主要遍历Collections集合的元素。
boolean hasNext(); //若被迭代的元素还没有被遍历,返回true Object next(); // 返回集合的下一个元素 void remove(); //删除集合上一次next ()方法返回的元素
迭代是取出集合元素的一种方式。
遍历ArrayList 或者遍历LinkList简单,遍历 Tree 实现机制不同,,而遍历 set 容器就难了。
import java.util.HashSet; import java.util.Iterator; class Student{
private int id; private String name; public Student(int id, String name){
this.id = id; this.name = name; } //overwrite public String toString(){
return this.id + ":" + this.name; } //overwrite hashCode() public int hashCode(){
return id * name.hashCode(); } //overwrite equals() public boolean equals(Object o){
Student s = (Student)o; return (s.id == this.id) && (s.name.equals(this.name)); } } public class Iterator1{
public static void f(){
HashSet hs = new HashSet(); hs.add(new Student(1,"Jack")); hs.add(new Student(2,"Bill")); hs.add(new Student(3,"Alice")); hs.add(new Student(4,"Cici")); Student st; Iterator it = hs.iterator(); //Poly while (it.hasNext()){
st = (Student)(it.next()); System.out.println(st); } } }
[java] 2:Bill [java] 1:Jack [java] 4:Cici [java] 3:Alice
用法:
Iterator iter = hs.iterator(); while(iter.hasNext()){
System.out.println(iter.next()); }
Java 集合中关于Iterator 和ListIterator的详解
为什么要将局部变量的作用域最小化
值传递和引用传递
当一个参数按照值的方式在两个方法之间传递时,调用者和被调用者其实是用的两个不同的变量——被调用者中的变量(原始值)是调用者中变量的一份拷贝,对它们当中的任何一个变量修改都不会影响到另外一个变量。
而当一个参数按照引用传递的方式在两个方法之间传递时,调用者和被调用者其实用的是同一个变量,当该变量被修改时,双方都是可见的。
Java 程序员之所以容易搞混值传递和引用传递,主要是因为 Java 有两种数据类型,一种是基本类型,比如说 int,另外一种是引用类型,比如说 String。
基本类型的变量存储的都是实际的值,而引用类型的变量存储的是对象的引用——指向了对象在内存中的地址。值和引用存储在 stack(栈)中,而对象存储在 heap(堆)中。
- 栈的优势是,存取速度比堆要快,仅次于直接位于 CPU 中的寄存器。但缺点是,栈中的数据大小与生存周期必须是确定的。
- 堆的优势是可以动态地分配内存大小,生存周期也不必事先告诉编译器,Java 的垃圾回收器会自动收走那些不再使用的数据。但由于要在运行时动态分配内存,存取速度较慢
基本类型和引用对象 在栈中,对象在队中。
字符串比较
再次复习 == 和equals的区别:
- “==”操作符用于比较两个引用(内存中的存放地址)是否相等,它们是否是同一个对象。
.equals()用于比较两个对象的内容是否相等。Object 的equals源码:
public boolean equals(Object obj) { return (this == obj); }可以看得出,Object 类的
.equals()方法默认采用的是“”操作符进行比较。假如子类没有重写该方法的话,那么“”操作符和.equals()方法的功效就完全一样——比较两个对象的内存地址或者对象的引用是否相等。但实际情况中,有不少类重写了
.equals()方法,因为比较内存地址太重了,不太符合现实的场景需求。String 类就重写了.equals()方法,源码如下所示。
public boolean equals(Object anObject) {
if (this == anObject) {
return true; } if (anObject instanceof String) {
String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) {
char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) {
if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
创建 字符串对象的两种方法:
String Duck = "Guua"; String Dog = new String("Whoof");
第一种是在字符串常量池(存储在方法区)中创建对象,并将对象的引用赋值给 Duck。第二种是通过 new 关键字在堆中创建对象,并将对象引用赋值给 Dog。
经过大量实例的分析,我们可以得出如下结论(也是对提问者的回答):
- 当比较两个字符串对象的内容是否相等时,请使用
.equals()方法。 - 当比较两个字符串对象是否相等时,请使用“==”操作符。
当然了,如果要进行两个字符串对象的内容比较,除了 .equals() 方法,还有其他可选的方法。
1)Objects.equals()
Objects.equals() 这个静态方法的优势在于不需要在调用之前判空。
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b)); }
如果直接使用 a.equals(b),则需要在调用之前对 a 进行判空,否则可能会抛出空指针 java.lang.NullPointerException。
Objects.equals("小萝莉", new String("小" + "萝莉")) // --> true Objects.equals(null, new String("小" + "萝莉")); // --> false Objects.equals(null, null) // --> true String a = null; a.equals(new String("小" + "萝莉")); // throw exception
2)String 类的 .contentEquals()
.contentEquals() 的优势在于可以将字符串与任何的字符序列(StringBuffer、StringBuilder、String、CharSequence)进行比较。
public boolean contentEquals(CharSequence cs) {
// Argument is a StringBuffer, StringBuilder if (cs instanceof AbstractStringBuilder) {
if (cs instanceof StringBuffer) {
synchronized(cs) {
return nonSyncContentEquals((AbstractStringBuilder)cs); } } else {
return nonSyncContentEquals((AbstractStringBuilder)cs); } } // Argument is a String if (cs instanceof String) {
return equals(cs); } // Argument is a generic CharSequence char v1[] = value; int n = v1.length; if (n != cs.length()) {
return false; } for (int i = 0; i < n; i++) {
if (v1[i] != cs.charAt(i)) {
return false; } } return true; }
从源码上可以看得出,如果 cs 是 StringBuffer,该方法还会进行同步,非常的智能化。不过需要注意的是,使用该方法之前,需要确保比较的两个字符串都不为 null,否则将会抛出空指针。
再强调一点,.equals() 方法在比较的时候需要判 null,而“==”操作符则不需要。
System.out.println( null == null); // --> true
3.4
CNKI CAJviewer
java继承
不过,子类无法继承父类的构造方法。如果父类的构造方法是带有参数的,代码如下所示:
public class Wanger {
int age; String name; public Wanger(int age, String name) {
this.age = age; this.name = name; } }
则必须在子类的构造器中显式地通过 super 关键字进行调用,否则编译器将提示以下错误:
修复后的代码如下所示:
public class Wangxiaoer extends Wanger{
public Wangxiaoer(int age, String name) {
super(age, name); } }
尽管一个类只能继承一个类,但一个类却可以实现多个接口
在java8以后,接口中可以添加使用default或者static修饰的方法,在这里我们只讨论default方法,default修饰方法只能在接口中使用,在接口中被default标记的方法为普通方法,可以直接写方法体。
java接口中的default方法
如果一个类继承了两个接口都有同名的default,则自己必须重写这个方法。如果一个类继承的父类和接口都有同名方法,则会继承父类的那个。
3.5
headfirstjava
异常
如果遇到编译器检查异常,就必须把有风险的包在try/catch 块中。❌ 也可以声明异常。
catch 可以多态化。✅
main方法必须处理所有未被处理的异常。❌ java虚拟机只好中断。
ducking 是声明 的意思。✅
运行时的异常必须处理或duck掉。✅
图形界面
第一个GUI:
package exerciseOfHeadFirst; import javax.swing.*; public class SimpleGui1 {
public static void main(String[] args){
JFrame frame = new JFrame(); JButton button = new JButton(); frame.setDefaultCloseOperation((JFrame.EXIT_ON_CLOSE)); // 在windows关闭时把程序结束掉 frame.getContentPane().add(button); //把button 加到frame 的pane上 frame.setSize(300,300); //设定frame大小 frame.setVisible(true); } }
序列化和文件
将序列化对象写入文件
//创建出文件的fileStream 对象,如果文件不存在,会自动被创建 FileOutputStream fileStream = new FileOutputStream("MyGame.ser"); //它能让你写入对象,但无法连接文件,所以需要参数的指引 ObjectOutputStream os = new ObjectOutputStream(fileStream); //将变量所引用的对象序列化并写入文件 os.writeObject(characterOne); os.writeObject(characterTwo); //关闭关联的数据串流 os.close();
一般,串流要两两来连接才能做有意义的事情——其中一个表示连接,另一个表示要被调用方法的。
Object———> 对象被碾平 —————> 当作字节处理 —–> 文件
ObjectOutputStream FileOutputerStream
Java对象的序列化和反序列化
当对象被序列化时,被该对象引用的实例变量也会被序列化(自动的)
package exerciseOfHeadFirst; import java.io.*; public class Box implements Serializable{
//仅告诉java虚拟机 它可以被序列化 private int width; private int height; //这两个值会被保存 public void setWidth(int w){
width = w; } public void setHeight(int h){
height = h; } public static void main(String[] args){
Box myBox = new Box(); myBox.setWidth(50); myBox.setHeight(20); try{
FileOutputStream fs = new FileOutputStream("foo.ser"); ObjectOutputStream os = new ObjectOutputStream(fs); os.writeObject(myBox); os.close(); }catch(Exception ex){
ex.printStackTrace(); } } }
运行结果就是在根目录下 创建了foo.ser 文件
解序列化:还原对象
FileInputStream fileStream = new FileInputStream("MyGame.ser"); //FileInputStream 知道怎么来连接文件 ObjectInputStream os =new ObjectInputStream(fileStream); // 它知道如何堆区对象,但是要考链接的stream提供文件存取 Object one = os.readObject(); Object two = os.readObject(); //每次调用readOBject 都会从stream中读出下一个对象,读取顺序与写入顺序相同,次数超过会抛出异常。 GameCharacter elf = (GameCharacter) one; GameCharacter elf = (GameCharacter) two; //因为返回值是Object类型,所以必须转换类型。 os.close();
过程:
1。对象从stream中读出来
2。java虚拟机通过存储的信息判断出对象的class 类型
3.Java虚拟机尝试加载对象的类。如果Java虚拟机找不到或无法加载该类,这Java虚拟机会抛出例外。
4.新的对象会被配置在堆上,但构造函数不会执行!这样会把对象的状态抹去又变成全新的。
5.如果对象在继承树有个不可序列化的祖先类,则该不可序列化类以及在它之上的类的构造函数(就算是可序列化的都一样)就会执行。一旦构造函数连锁启动之后将无法停止。也就是说,从第一个不可序列化的父类开始,全部都会重新初始转入。
6.对象的实例变量会被还原成序列化时的状态值。transient 变量会被赋值null的对象引用或primitive主数据 类型的默认为0,false等值。
注意:static 变量会维持类原本的样子,而不是存储时的样子。
本节要点
你可以通过序列化来存储对象的状态。
使用Java.io 的ObjectOutputStream来序列化对对象。
Stream是连接串流或是链接用的串流。
连接串流用来表示源或目的地、文件、网络套接字连接。
链接用串流用来衔接链接串流。
用FileOutputStream链接ObjectOutputStream来将对象序列化到文件上。
调用ObjectOutputStream的write(theObject)来将对象序列化,不需要调用FileOutputStream的方法。
对象必须实现序列化这个接口才能被序列化。如果父类实现序列化,则子类就自动地实现,不管有没有明确的声明。
当对象被序列化时,整个对象版图都会被序列化。这代表它的实例变量所引用的对象也会被序列化。
如果又不能被序列化的对象,执行期间就会抛出异常。
除非该实例被标记为transient。否者该变量子啊还原的时候会被赋予null或primitive主数据类型的默认值。
在解序列化时,所有的类都必须能让Java虚拟机找到。
readObject()返回的类型和是Object,因此解序列化需转化为原来的类型。
git
版本控制 、团队协作
集中式版本控制:SVN、CVS、VSS 会有单点故障
分布式版本控制:Git、Mercurial、Bazaar、Darccs 本地有所有历史版本
优势:完整性保证:Hash
3.7
HashSet
HashMap
将字符串写入文本文件
Q&A
序列化适用于存储数据给非Java 程序使用的情景。 ❌
对象的状态只能用序列化来存储。 ❌
ObjerctOutputStream 是个用来存储序列化对象的类。✅
链接串流可以单独使用或与链接串流使用。 ❌
调用writeObject() 可能会存储好几个对象。✅
所有类都是默认可序列化的。 ❌
当对象还原时,构造函数不会执行。✅
网络
看完视频后来巩固
Socket 是代表两台机器之间网络连接的对象(jave.net.Socket)。
Socket chatSocket = new Socket("196.164.1.103",5000); //TCP端口号
TCP是16位端口,0~65525
使用BufferedReader 从Socket上读取数据
① 建立对服务器的Socker连接
② 建立连接到Socket 上低层数额u串流的InputStreamReader
③ 建立BufferedReader 来读取
Socket chatSocket = new Socket("127.0.0.1",5000); InputStreamReader stream = new InputStreamReader(chatSocket.getInputStream()); //InputStreamReader 是低层和高层串流间的桥梁。 BufferedReader reader = new BufferedReader(stream); //将BufferedReader 链接到 InputStreamReader String message = reader.readLine();
用PrintWriter写数据到Socket上
Socket chatSocket = new Socket("127.0.0.1",5000); PrintWriter writer = new PrinterWriter(chatSocket.getOutputStream()); // 可以连接String 和Socket两端 writer.println("message to send"); writer.print("another message");
机组

解:可以找到64K 个字节,即从0~ 2^16-1 或者0~65535。存储字长为32位,即一个字有四个字节,则有16K个字。(1)寻址范围为16K。
(本题没有将高位字节为字地址还是低位)

(2)则字的地址为上图红色。
在主存中要最小化到字节, 字号 (16K–>14位)+字内地址(4–>2位)

解:(1)地址码为18位,则可访问的存储单元为218个,又因为是8位机,则总存储容量位218*8b =256KB。
(2)用256KB 除以32K*8 =8个模块版
(3)依然做除法,16片 (4)乘法 16*8
(5)18位地址码如何分配,(模块版号,RAM芯片,片内)
(8个模块3位,16块芯片8组3位,12位)
特别注意:8位机每次访问8位数据!则要一次选两片芯片做位扩展。


解:单看译码器,要使其工作,G1为高电平,G2A 、G2B为低电平。 为1,0,0输入。
0~4K为系统区 0~4k-1 选用ROM(4K×8)4K~16K-1为用户区,选用RAM(12k×8)
①写出对应的二进制地址10 A9 A8 A7 A6 A5 A4 A3 A2 A1 A0
0000 0000 0000 0000 为系统区起始
0000 1111 1111 1111 为系统区最后
0001 0000 0000 0000 为RAM1 起始
0001 1111 1111 1111 为RAM1 最后
则可以看出A12A13为芯片选择信号。RAM选择4K×8刚好,而ROM有2K×8和4K×4的要结合题目选择,因为4K占0~11位刚好。
②分配地址线:cpu 的A0~A11与RAM和ROM的相连
CBA由A14A13A12连接
3.8–3.9
JAVA
如何使用成员内部类?两种方式
1、间接方式:在外部类的方法中,使用内部类;然后main 只是调用外部类的方法。
2.直接方式:公式: 外部类名称.内部类名称 对象名 = new 外部类名称(). new 内部类名称();
匿名内部类
== 基本数据类型:比较的是值; 引用数据类型;比较的是地址值。
this 哪个对象带调用的方法,则this 就是这个对象。
多态弊端:无法使用子类特有的内容(属性,方法)
解决方法:向下转型(强转) 对象转换
Numpy
使用np.asarray()同样可以返回得到一个ndarray的数组。但是使用np.array()返回的是一个允许被更改的ndarray,np.asarray()返回的ndarray不允许被更改。
3.10–3.11
Java
日期和时间类
System.currentTimeMillis() 获取当前系统毫秒值(从1970-01-01到现在的毫秒) 为Long类型
一天有86,400,000毫秒 。中国属于东八区, 起始时间为08:00。
java.text.DateFormat 类
是一个抽象类,extends format 。是日期/时间格式化的子类。格式化(日期–>文本),解析(文本–>日期)
import java.text.SimpleDateFormat;
/* 成员方法: String format(Date date) 格式化 Date parse(String sourse) 把符合模式的字符串,解析为Date日期 java.text.SimpleFormat extends DateFormat 构造方法: SimpleDateFormat(String pattern) 用给定的模式和默认语言日期格式符号构造SimpleDateFormat 参数: String pattern: 传递指定的模式 模式:(详见下截图 ) y 年 M 月 d 日 H 时 m 分钟 s 秒 */
Date d = new Date(3000L);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); //更加美观输出
String format = sdf.format(d);
sout(d);
// Parse 方法转换:
String str = "2088年08月08日 08:08:08";
Date parse = sdf.parse(str);

java.util.Calendar 类
是一个抽象类,初始化:
Calendar now = Calendar.getInstance();//用一个父类接收自子类的对象是 多态。
System类
java.lang.System类中提供了大量的静态方法
数组复制:
import java.util.Arrays;
public class SystemTest {
public static void main(String[] args) {
demo02();
}
private static void demo02() {
int[] src = {
1,2,3,4,5};
int[] dest = {
6,7,8,9,10};
System.out.println("复制前目标数组:" + Arrays.toString(dest));
System.arraycopy(src, 0,dest,0,3);
System.out.println("复制后目标数组:" + Arrays.toString(dest));
}
}
//
复制前目标数组:[6, 7, 8, 9, 10]
复制后目标数组:[1, 2, 3, 9, 10]
String 类
字符串是常量,在创建后不能改变。其底层是一个final修饰的数组。 private final byte[] value;
进行字符串相加,内存会有多个字符串,效率很低。 String s =“a”+“b”+“c”=“abc”;
StringBuilder 类
字符串缓冲区,可以提高效率,底层是一个没被final的数组。 byte[] value = new byte[16];初始容量是16
(StringBuilder 不是线程安全的类)
public class DemoStringBuilder {
public static void main(String[] args) {
StringBuilder bu1 = new StringBuilder("asd");
//append 方法 返回的都是this
StringBuilder bu2 = bu1.append("009");
System.out.println(bu1);
System.out.println(bu2);
System.out.println(bu1==bu2);
}
}
所以append方法无需接受
asd009
asd009
true
既然是返回this,就可以链式编程
bu1.append("").append("").append("").reverse();
String 和StringBuilder 的相互转换,使用StringBuilder的构造方法。toString 方法。
public class DemoToString {
public static void main(String[] args) {
String str = "hello";
StringBuilder sb = new StringBuilder(str); //直接传入String 进行转换
sb.append("world");
String s = sb.toString(); //转化回String
}
}
包装类
在后面的泛型上会经常用到
将数字转换为字符串
//直接加上空字符串
String s = 5 + "";
Collection集合
- list接口
1.有序的集合(存入和取出的顺序相同)
2.允许存储重复的元素。
3.有索引,可用for遍历
- Vector集合
- ArrayList集合 :底层是数组实现的,查询快,增删慢
- LinkList集合 : 底层是链表实现的,查询慢,增删快
- set接口
1.不允许存储重复元素
2.没有索引
- Treeset集合 (无序) : 底层是 二叉树实现的,一般用于排序
- HashSet集合 (无序) :底层是哈希表+(红黑树)实现的,无索引
LinkedHashSet 集合 :底层是哈希表+链表实现的,无索引,可以保证存储顺序
Collection 集合常用方法
boolean add(E e);
boolean remove(E e);
void clear(); 清空所有i元素
boolean contains(E e);
boolean isEmpty();
int size();
Object[] toArray(); 返回一个数组
Collection<String> coll = new ArrayList<>(); //创建
Iterator 接口
public E next() //返回下一个元素
public boolean hasNext(); //如果有元素迭代返回True
增强for循环:底层也是使用迭代器
for (集合/数组的数据类型 变量名 : 集合名/数组名){
sout(变量名)
}
public class EnhancedFor {
public static void main(String[] args) {
int[] arr = {
1,2,3,4,5};
for(int i:arr){
//遍历数组
System.out.println(i);
}
ArrayList<String> list = new ArrayList<>();
list.add("sdasd");
list.add("1222");
list.add("00000");
for(String s :list){
System.out.println(s);
}
}
}
3.14–3.17
泛型
集合不用泛型,默认的类型是object类型,可以存储任意类型的数据
坏处是:不安全,会发生异常
泛型的好处:避免类型转换;把运行期的异常提升到了编译期
private static void show(){
ArrayList list =new ArrayList(); //没使用泛型的情况
list.add("abc");
list.add(1);
Iterator it = list.iterator();
while(it.hasNext()){
Object next = it.next();
System.out.println(next);
//向下转型
String s = (String)next;
System.out.println(s.length());
}
abc
3
1
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.test.demo02.Demo001.show(Demo001.java:21)
at com.test.demo02.Demo001.main(Demo001.java:8)
想调用String 的方法,但是出错,因为Integer不能强制转换为String
含有泛型的方法
public <M> void method(M m){
//泛型中用什么表示都行
sout(m);
}
//含有泛型的方法,在调用方法的时候确定泛型的数据类型,传递什么类型的参数,泛型就是什么类型
泛型通配符
不知道使用什么类型来接收,可以使用 ? 不能创建对象,只能作为方法使用。
import java.util.ArrayList;
import java.util.Iterator;
public class Generic {
public static void main(String[] args) {
ArrayList<Integer> list01 =new ArrayList<>();
list01.add(1);
list01.add(2);
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("b");
printArrayList(list01);
printArrayList(list02);
}
//定义一个方法,可以遍历所有类型的ArrayList 集合
public static void printArrayList(ArrayList<?> list){
Iterator<?> it = list.iterator();
while(it.hasNext()){
//注意 it.hasNext 方法取出的是Object类型,可以接收任意数据类型
Object o = it.next();
System.out.println(o);
}
}
}
//注意定义的时候不能用 ,只能作为参数传递时使用
ArrayList<?> list03 = new ArrayList<?>(); //此处 报错
通配符高级使用 ——受限类型
之前设置泛型的时候,实际上可以任意设置的。但在Java的泛型可以指定泛型的上限和下限。
泛型的上限:(只能接收该类型及其子类)
类型名称 <? extends 类> 对象名称泛型的下限: (只能接收该类型及其父类)
类型名称 <? super 类> 对象名称
能看懂源码就行。
类与类的继承关系:
Integer extends Numbers extends Object
String extends Object
红黑树
特点:趋近于平衡树(左孩子和右孩子数目相等),查询速度很快,查询叶子最大速度和最小速度不超过2倍。
约束:节点是红 或黑色
根节点是黑色的
叶子节点(空) 也是黑色的
每个红色节点的字节点都是黑色的
任何一个节点到其每一个叶子节点的所有路径黑色节点数相同
ArrayList 查询快,增删慢,因为每次增删都在底层复制数组。
LinkedList集合
LinkedList<String> linked = new LinkedList<>():
linked.add("a"); //快速添加元素
linked.addLast('sda'); //在列表末尾添加,和 add等效
linked.addFirst('www'); //在列表开头添加
linked.push(); //将元素推入此队列表示的堆栈 和addfirst 等效
linked.getFirst(); //获取第一个元素
linked.getLast();
linked.isEmpty();
linked.clear(); //清空
set接口
import java.util.HashSet;
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);
// 不能使用for循环,使用迭代器
Iterator<Integer> it =sse.iterator();
while(it.hasNext()){
Integer n =it.next();
sout(n);
}
//增强for 遍历
for(Integer i: set){
...;
}
哈希表
哈希值: 是十进制整数,由系统随机给出,是一个逻辑地址(模拟的),不是实际物理地址。
// Object类一个方法返回哈希值 int hashCode()
// 源码: public native int hashCode(); native 的意思是调用本地操作系统的方法。
// toString() 方法 也是输出哈希值,是十六进制的

如果同一个地址下元素超过了8位,就会把链表转成红黑树(提高查询效率)
所以HashSet 的底层 数组+链表 或者 数组+红黑树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6Q6LIY9R-1620310869308)(C:\Users\祝金良\AppData\Roaming\Typora\typora-user-images\image-20210322175356943.png)]
HashSet 保证元素不重复的条件:重写了hashCode 和 equals 方法
System.out.println(o);
}
}
}
通配符高级使用 ——受限类型
之前设置泛型的时候,实际上可以任意设置的。但在Java的泛型可以指定泛型的上限和下限。
> 泛型的上限:(只能接收该类型及其子类)
>
> ```
> 类型名称 <? extends 类> 对象名称
> ```
>
> 泛型的下限: (只能接收该类型及其父类)
>
> ```
> 类型名称 <? super 类> 对象名称
> ```
能看懂源码就行。
类与类的继承关系:
Integer extends Numbers extends Object
String extends Object
红黑树
特点:趋近于平衡树(左孩子和右孩子数目相等),查询速度很快,查询叶子最大速度和最小速度不超过2倍。
约束:节点是红 或黑色
> 根节点是黑色的
>
> 叶子节点(空) 也是黑色的
>
> 每个红色节点的字节点都是黑色的
>
> 任何一个节点到其每一个叶子节点的所有路径黑色节点数相同
ArrayList 查询快,增删慢,因为每次增删都在底层复制数组。
LinkedList集合
```java
LinkedList<String> linked = new LinkedList<>():
linked.add("a"); //快速添加元素
linked.addLast('sda'); //在列表末尾添加,和 add等效
linked.addFirst('www'); //在列表开头添加
linked.push(); //将元素推入此队列表示的堆栈 和addfirst 等效
linked.getFirst(); //获取第一个元素
linked.getLast();
linked.isEmpty();
linked.clear(); //清空
set接口
import java.util.HashSet;
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
set.add(3);
// 不能使用for循环,使用迭代器
Iterator<Integer> it =sse.iterator();
while(it.hasNext()){
Integer n =it.next();
sout(n);
}
//增强for 遍历
for(Integer i: set){
...;
}
哈希表
哈希值: 是十进制整数,由系统随机给出,是一个逻辑地址(模拟的),不是实际物理地址。
// Object类一个方法返回哈希值 int hashCode()
// 源码: public native int hashCode(); native 的意思是调用本地操作系统的方法。
// toString() 方法 也是输出哈希值,是十六进制的

如果同一个地址下元素超过了8位,就会把链表转成红黑树(提高查询效率)
所以HashSet 的底层 数组+链表 或者 数组+红黑树
[外链图片转存中…(img-6Q6LIY9R-1620310869308)]
HashSet 保证元素不重复的条件:重写了hashCode 和 equals 方法
HashSet存储自定义类型元素:必须保证也重写以上方法 (视频P268)
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/106904.html
