【学习笔记】《Java编程思想》 第8~11章
第八章 多态
- 多态的条件:
1. 要有继承
2.父类对象引用子类对象
3. 要有方法的重写
- 多态的作用:消除类型之间的耦合关系。
- 将一个方法调用与一个方法主体关联起来称作绑定。若在程序执行前进行绑定,叫做前期绑定;在运行时根据对象的类型进行绑定,叫做后期绑定,也叫动态绑定、运行时绑定。
- Java中除了static方法和final方法之外,其他所有的方法都是后期绑定。所以final的作用还有关闭动态绑定。
- 只有非private方法才可以被覆盖,但是还需要密切注意覆盖private方法的现象,这时虽然编译器不会报错,但是也不会按照我们的预期的执行。
- 如果某个子对象要依赖于其他对象,销毁的顺序应该和初始化顺序相反。
- 域是不具有多态性的,只有普通的方法调用是多态的。如果直接访问某个域,这个访问就将在编译期进行解析,即域是静态解析的。静态方法也是不具有多态性的。
第九章 接口
- 抽象方法和抽象类:
抽象方法是不完整的,仅有声明而没有方法体
abstract void f();
包含抽象方法的类叫做抽象类;如果一个类包含一个或多个抽象方法,该类必须被定义为抽象的
如果从一个抽象类继承,并想创建该类的对象,那么就必须为基类中的所有抽象方法提供方法定义;如果不这样做,那么导出类也是抽象类,且编译器会强制我们用abstract关键字来限制这个类。 interface这个关键字产生一个完全抽象的类,它根本就没有提供任何具体实现
要让一个类遵循某个特定接口(或一组接口),需要使用implements关键字
- 如果从一个非接口的类继承,那么只能从一个类继承;可以继承多个接口
- 接口可以多继承接口来扩展,接口还可以嵌套。
- 接口是实现多重继承的途径,而生成遵循某个接口的对象的典型方式就是工厂方法。在工厂对象上调用的是创建方法,而该工厂对象将生成接口的某个实现的对象。
- 接口可以包含域,且隐式地是
static
和final
的。 - 接口关键字
interface
前可以添加public
修饰符,不加默认是包访问权限,接口的方法默认都是public
的。
第十章 内部类
- 将一个类的定义放在另一个类的定义内部,这就是内部类。
- 从外部类的非静态方法之外的任意位置创建某个内部类的对象,那么必须具体地指明这个对象的类型OuterClassName.InnerClassName。
非static的普通内部类自动拥有对其外围类所有成员的访问权(包括private)
- 如果需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟.this
public class DotThis {
void f() {
System.out.println("DotThis.f()");
}
public class Inner {
public DotThis outer() {
return DotThis.this;//通过.this返回外部类对象
}
}
public Inner inner() {return new Inner();}
public static void main(String[] args) {
DotThis dotThis = new DotThis();
DotThis.Inner dtInner = dotThis.inner();
dtInner.outer().f();
}
}如果要创建内部类对象,必须使用外部类对象和.new
public class DotNew {
public class Inner {}
public static void main(String[] args) {
DotNew dn = new DotNew();
DotNew.Inner dni = dn.new Inner();
}
} - 如果拥有的是抽象类或者具体类,而不是接口,那么就只能使用内部类实现多重继承
public class Example1 {
public String getName() {
return "llb";
}
}
public class Example2 {
public int getAge() {
return 25;
}
} public class MultiImplementation {
private class test1 extends Example1 {
public String getName() {
return super.getName();
}
}
private class test2 extends Example2 {
public int getAge() {
return super.getAge();
}
}
public String getName() {
return new test1.getName();
}
public int getAge() {
return new test2.getAge();
} public static void main(String[] args) {
MultiImplementation my = new MultiImplementation();
System.out.println("姓名: " + my.getName());
System.out.println("年龄: " + my.getAge());
}
} 局部内部类是指内部类定义在方法或作用于内
- 局部内部类不能有访问说明符
- 局部内部类可以访问当前代码块内的常量以及此外围类的所有成员
局部内部类会跟着其他类一起通过编译,但是在定义该局部内部类的方法或作用域之外,该局部内部类是不可用的
- 内部类声明为
static
时,不再包含外围对象的引用.this
,称为嵌套类(与C++嵌套类大致相似,只不过在C++中那些类不能访问私有成员,而在Java中可以访问)。
- 创建嵌套类,不需要外围对象。
- 不能从嵌套类的对象中访问非静态的外围对象。public class OuterClass {
private static String address = "Shanghai";
public static class StaticInnerClass {
public String getAddress() {
return address;
}
}
public static void main(String[] args) {
OuterClass.StaticInnerClass sic = new
OuterClass.StaticInnerClass();
String address = sic.getAddress();
System.out.println(address);
}
} 匿名内部类创建方式为:
new 外部类构造器(参数列表)或接口 {}
- 在定义类的同时就生成了该内部类的一个实例,随后该类的定义会消失,所以匿名内部类不能被重复使用
- 匿名内部类必须继承一个父类或者实现一个接口,但是也只能继承一个父类或实现一个接口
- 匿名内部类中不能定义构造方法(没有类名),不能存在任何的静态成员变量和静态方法
- 匿名内部类不能是抽象的,它必须实现所继承的类或者实现的接口中的全部抽象方法
public interface Contents {
int value();
}
public class Parcel7 {
public Contents contents() {
return new Contents() {
private int i = 1;
public int value() { return i; }
};
} //等价于
/*
class MyContents implements Contents {
private int i = 1;
public int value() { return i; }
}
public Contents contents() { return new MyContents(); }
*/ public static void main(String[] args) {
Parcel7 parcel7 = new Parcel7();
Contents c = parcel7.contents();
}
}给匿名内部类传递参数时,若该形参在内部类被使用,那么该形参必须被声明为final
public class Parcel9 {
//dest是一个在外部定义的对象,必须将其定义为final参数引用
public Destination destination(final String dest) {
return new Destination() {
private String label = dest;
@Override
public String readLabel() {
return label;
}
};
}
public static void main(String[] args) {
Parcel9 parcel9 = new Parcel9();
Destination destination = parcel9.destination("Shanghai");
System.out.println(destination.readLabel());
}
}- 为什么要是final?内部类并不是直接调用方法传递的参数,而是利用自身的构造器对传入的参数进行备份,自己内部方法调用的实际上是自己的属性而不是外部方法传递进来的参数,在内部类中的属性和外部方法的参数两者看似是同一个东西,但实际上却不是,也就是说在内部类中对属性的修改并不会影响到外部的形参,如果内部类中的属性改变了,而外部方法的形参却没有改变,这是难以接受的,为了保证参数的一致性,就规定使用final来避免两者不同时变化的情况发生。
每个类都会产生一个.class文件,其中包含了如何创建该类型的对象的全部信息;内部类也必须生成有个.class文件以包含它们的class对象信息,其命名规则是:
外围类的名字,加上”$“,再加上内部类的名字,如果时匿名内部类,编译器会简单地产生一个数字作为其标识符,例如:
Outer$Inner.class
Outer$1.class
第十一章 持有对象
- Collection是一个集合接口,提供了对集合对象进行操作的通用接口方法
Collections是一个包装类,包含有各种集合操作的静态方法,此类不能实例化,就像一个工具类,服务于Collection框架
Collection接口是最基本的集合接口,一个Collection代表一组Object,即Collection的元素 List,Set,Queue接口都是Collection接口的实现
- List:必须按照插入的顺序保存元素
- Set:不能有重复的元素
- Queue:按照队列的规则来确定对象产生的顺序(通常与元素插入的顺序相同)
- 在Java.util包中的Arrays和Collections类中都有很多实用方法,可以在Collection中添加一组元素;Arrays.asList()方法接受一个数组或是一个用逗号分割的元素列表(使用可变参数),并将其转换为一个List对象;Collections.addAll()方法接受一个Collection对象,以及一个数组或是一个用逗号分割的列表,将元素添加到Collection中
import java.util.*; public class AddingGroups {
public static void main(String[] args) {
Collection<Integer> collection =
new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4, 5));
Integer[] moreInts = {6, 7, 8, 9, 10};
collection.addAll(Arrays.asList(moreInts));//更快,但不够灵活
Collections.addAll(collection, 11, 12, 13, 14, 15);
Collections.addAll(collection, moreInts);//更加灵活
List<Integer> list = Arrays.asList(16, 17, 18, 19, 20);
list.set(1, 99);
}
} Arrays类似于Collections,是一个工具类
Arrays.asList()返回一个受指定数组支持的固定大小的列表,可以用来将数组转换成List
反过来,利用List的toArray()方法,可以将List转换成数组
容器的打印
必须使用Arrays.toString()来产生数组的可打印表示
List
ArrayList:随机访问,但是在List的中间插入或移除元素时较慢
LinkedList:通过代价较低的在List中间进行的插入和删除操作,提供了优化的顺序访问;随机访问较慢
ArrayList常见方法
contains(Object o):确定某个对象是否在列表中
remove(int index):移除指定位置上的元素
indexOf(Object o):返回列表中首次出现指定元素的索引,如果不包含该元素,返回-1
add(E e):将制定元素添加到此列表的尾部
add(int index, E e):将指定元素插入到指定位置
迭代器是一个对象,它的工作是遍历并选择序列中的对象
Java中的Iterator只能单向移动,只能用来:
- 使用方法iterator()要求容器返回一个Iterator;Iterator准备好返回序列的第一个元素
- 使用next()获得序列中的下一个元素
- 使用hasNext()检查序列中是否还有元素
- 使用remove()将迭代器新近返回的元素删除
LinkedList常见方法
addFirst(E e)/addLast(E e):将元素添加到列表的开头/结尾
getFirst()/element():返回列表的第一个元素
peek()/peekFirst():获取但不移除列表的第一个元素
offer(E e)/offerLast(E e):将元素插入到列表末尾
Queue
队列时一个典型的先进先出(FIFO)的容器,即从容器的一端放入事物,从另一端取出,并且事物放入容器的顺序与取出的顺序是一样的
LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以用作Queue的一种实现,也可以将LinkedList向上转型为Queue
Set
Set不保存重复的元素;Set最常被使用的是测试归属性,我们可以很容易地询问某个对象是否在某个Set中
存储元素的方式:
HashSet:使用散列函数
LinkedHashSet:使用散列,但是看起来使用了链表来维护元素的插入顺序
TreeSet:将元素存储在红-黑树结构中
Map:一组成对的“键值对”对象,允许使用键来查找值;映射表允许我们使用另一个对象来查找某个对象,它被称为“关联数组”,因为它将某些对象与另外一些对象关联在了一起,或者被称为“字典”
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
更复杂的形式
Map<Integer, List<String>> map =
new HashMap<Integer, List<String>>();
map.put(1, rrays.asList("lv", "long", "bao"));map的键是一个Set,值是一个Collection
Map常见方法
get(Object o):返回指定键所映射的值,如果不包含该键的映射关系,返回null
put(K key, V value):将指定的值与此映射中的指定键关联,如果已经存在映射关系,更新值
hashCode():返回此映射的哈希码值
Map的三种实现
HashMap:基于“拉链法”实现的散列表,一般用于单线程中,不是线程安全的
HashTable:基于“拉链法”实现的散列表,一般用于多线程中,是线程安全的
TreeMap:有序的散列表,通过红黑树实现的,一般用于单线程中存储有序的映射
- 总结:
- 数组将数字与对象联系起来:它保存类型明确的对象,查询对象时,不需要对结果做类型转换;它可以时多维的,可以保存基本类型的数据;但是,数组一旦生成,其容量不能改变
- Collection保存单一的元素,而Map保存关联的键值对:有了Java泛型,你就可以指定容器中存放的对象类型,因此你就不会将错误类型的对象放置到容器中,并且在从容器中获取元素时,不必进行类型转换;各种Collection和Map都可以在你向其中添加更多的元素时,自动调整其尺寸;容器不能持有基本类型,但是自动包装机制会仔细地执行基本类型到容器中所持有包装器类型之间的双向装换
- 像数组一样,List也建立数字索引与对象的关联,因此,数组和List都是排好序的容器;List能够自动扩充容量
- 如果要进行大量的随机访问,就使用ArrayList;如果要经常从表中间插入或删除元素,则应该使用LinkedList
- 各种Queue以及栈的行为,由LinkedList提供支持
- Map是一种将对象(而非数字)与对象相关联的设计:HashMap设计用来快速访问;TreeMap保持“键”始终处于排序状态,所以没有HashMap快;LinkedHashMap保持元素插入的顺序,但是也通过散列提供了快速访问能力
- Set不接受重复元素:HashSet提供了最快的查询速度;TreeSet保持元素处于排序状态;LinkedHashSet以插入顺序保存元素
- 新程序中不应该使用过时的Vector,Hashtable和Stack(原因参考:https://www.cnblogs.com/fudashi/p/7214609.html)
【学习笔记】《Java编程思想》 第8~11章的更多相关文章
- 学习笔记-Java编程思想
2016-01-03 Swith(整数选择因子):必须是int或char这样的整数值. Java中不包含goto语句,但是可以通过标识符实现类似的控制.
- 《python基础教程(第二版)》学习笔记 文件和素材(第11章)
<python基础教程(第二版)>学习笔记 文件和素材(第11章) 打开文件:open(filename[,mode[,buffering]]) mode是读写文件的模式f=open(r' ...
- 异常笔记--java编程思想
开一个新的系列,主要记一些琐碎的重要的知识点,把书读薄才是目的...特点: 代码少,概念多... 1. 基本概念 异常是在当前环境下无法获得必要的信息来解决这个问题,所以就需要从当前环境跳出,就是抛出 ...
- 《Java编程思想》第一二章
前段时间一直通过网络教程学习Java基础,把面向对象部分学完之后本来打算继续深入学习,但是感觉自己操之过急了,基础根本不够扎实,所以入手了一本<Java编程思想>,希望先把基础打好,再深入 ...
- Java编程思想 4th 第2章 一切都是对象
Java是基于C++的,但Java是一种更纯粹的面向对象程序设计语言,和C++不同的是,Java只支持面向对象编程,因此Java的编程风格也是纯OOP风格的,即一切都是类,所有事情通过类对象协作来完成 ...
- Java编程思想 4th 第1章 对象导论
所有编程语言都提供抽象机制. 面向对象编程似乎是一种很好的编程思想和方式,面向对象编程中的对象简洁描述是:对象具有状态.行为和标识.状态指的是数据存储,存储的数据能反应状态:行为指的是方法,方法表示对 ...
- Java编程思想 4th 第3章 操作符
有了数据,还需要进行数据间的运算,因此Java中也有数据间运算的各种符号,书本称之为操作符,正确的翻译应该是运算符. Java中的运算符同C++相同,运算符同运算符对象构成表达式,表达式是运算对象及运 ...
- Think in Java(Java编程思想)-第2章 一切都是对象
1. String s = "asdf"//创建一个String引用,并初始化. String s = new String("asdf")//创建一个新对象, ...
- 《Java编程思想》学习笔记(二)——类加载及执行顺序
<Java编程思想>学习笔记(二)--类加载及执行顺序 (这是很久之前写的,保存在印象笔记上,今天写在博客上.) 今天看Java编程思想,看到这样一道代码 //: OrderOfIniti ...
- [Java编程思想-学习笔记]第3章 操作符
3.1 更简单的打印语句 学习编程语言的通许遇到的第一个程序无非打印"Hello, world"了,然而在Java中要写成 System.out.println("He ...
随机推荐
- Hadoop学习之路(4)Intelij+Maven搭建Hadoop项目
1创建工程 点击project--Maven--next 2通过maven导入项目依赖jar包 (1)设置maven自动导入依赖jar包 勾选 Import Maven projects automa ...
- 853. 有边数限制的最短路(Bellman-ford算法模板)
给定一个n个点m条边的有向图,图中可能存在重边和自环, 边权可能为负数. 请你求出从1号点到n号点的最多经过k条边的最短距离,如果无法从1号点走到n号点,输出impossible. 注意:图中可能 存 ...
- JS中axios使用注意点
今天遇到这样一个问题,前端会同时弹出成功和失败的两个提示框,由于不是本人操作,也没有怀疑是前端代码的问题,就索性根据后端的日志作为分析依据,开始个人以为是后端接口上班了两次结果,一个是成功,另外一个是 ...
- 一些java基础知识的备忘
接口和抽象类的区别是什么? 接口的方法默认是 public,所有方法在接口中不能有实现(Java 8 开始接口方法可以有默认实现),而抽象类可以有非抽象的方法. 接口中除了static.final变量 ...
- CodeForces 1144C
链接 https://vjudge.net/problem/CodeForces-1144C #include<bits/stdc++.h> using namespace std; in ...
- 1.mysql卸载重新安装问题
前言:在开发过程中,MySQL数据库是很频繁使用的数据库,但是有时候,数据库一单出错,或者其他原因,想要重装数据库,难免会遇到MySQL重装之后服务启不来,,下面我就跟大家讨论下如何干净的卸载MySQ ...
- MongoDB geonear和文本命令驱动程序2.0
文本查询,q作为查询字符串: coll.FindAsync<Foo>(Builders<Foo>.Filter.Text(q)); 文本查询需要一个文本索引.要从C#创建代码, ...
- MVC理解(全程白话不拽词)
我所发的所有博客只为了给想干程序员,但是基础没有或者很差,刚入职场的人 所有的观点不一定准确,我不懂的或者不理解的都会备注出来 先说MVC MVC理解为:M = Model = 数据库表里面每 ...
- Unable to create initial connections of pool. spring boot mysql
Unable to create initial connections of pool. 在链接url里添加 将useSSL=true改为useSSL=false 只能说明服务器没有打开SSL功能
- 在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvoke。”
出现场景: From1中事件B绑定在事件A,事件A由工厂模式下的设备产生,当离开Form1时,设备中的事件A仍然会触发事件B,此时就会导致如上问题 原因(个人理解): 1.Form1已经被销毁了,但仍 ...