Java基础

学习/java


1. 对象 Object (Is a/Is like)
	a. 向上转型 upcasting (解耦)
		i. 圆形也是一种形状
	b. 向下转型
		i. 参数化类型机制(Parameterized Type Mechanism)
	c. 多态(Polymorphism)--动态绑定实现多态性
	d. 集合 collection
		i. List 用于保存序列
			1. Arraylist
			2. Linklist
		Ii. 关联数组 Map  用于将对象与其他对象关联
		Iii. 队列 queue
		Iv. 树 Tree
		v. 栈 stacck
		Vi. 堆 heap
	e. 数据存储
		i. Register
		Ii. Stack
		Iii. Heap
		Iv. Rom
		v. Non ram
		Vi. Constant storage
	f. 自动装箱
	g. 方法名和参数列表统称为方法签名(signature of the
	Method)。
	h. 当返回类型为 void 时,return 关键字仅用于退出方法
	i. 引用静态变量有两种方法
		i. 通过一个对象来定位它,例如 st 2.I
		Ii. 通过类名直接引用它,这种方式对于非静态成员则不可行
2. 封装
	a. 包访问权限
		i. 把public 关键字从类中去掉,给予它包访问权限。
	b. 每个编译单元(即每个文件)中只能有一个public 类。这表示,每个编译单元有
	一个公共的接口用public 类表示。该接口可以包含许多支持包访问权限的类。一
	旦一个编译单元中出现一个以上的public 类,编译就会报错。
3. 复用
	a. “继承”(Inheritance)
		a. 多态(Polymorphism)
	b. “组合”(Composition)已经被多次使用。你仅需要把对象的引用
	(object references)放置在一个新的类里,这就使用了组合. 
   c.     每个非基本类型对象都有一个
	toString() 方法,在编译器需要字符串但它有对象的特殊情况下调用该方法.
	a. 为了允许继承,一般规则是所有字段为私有,所有方法为公共
	b. Java 不直接支持的第三种重用关系称为委托
	c. final 类禁止继承,类中所有的方法都被隐 式地指定为 final,所以没有办法覆写它们。你可以在 final 类中的方法加上 final 修饰 符,但不会增加任何意义
	d. 构造器 也是一个 static 方法尽管它的 static 关键字是隐式的。因此,准确地说,一个类当它 任意一个 static 成员被访问时,就会被加载
	e. 多态是面向对象编程语言中,继数据抽象和继承之外的第三个重要特性
	f. 通用准则:使用继承表达行为的差异,使用属性表达状态的变化
4. 接口
	a. 接口的典型使用是代表一个类的类型或一个形容词,如Runnable 或Serializable,而抽象类通常是类层次结构的一部分或一件事物的类型,如String 或ActionHero。
	b. Java 8 允许接口包含默认方法和静态方法,接口同样可以包含属性,这些属性被隐式指明为static 和final。
	c. 增加默认方法的极具说服力的理由是它允许在不破坏已使用接口的代码的情况下,在接口中增加新的方法。默认方法有时也被称为守卫方法或虚拟扩展方法。
5. 多继承
6. 内部类
	a. 内部类自动拥有对其外部类所有成员的访问权
		i. 当某个外部类的对象创建了一个内部类对象时,此内部类对象必定会秘密地获一个指向那个外部类对象的引用。然后,在你访问此外部类的成员时,就是用那个引用来选择外部类的成员
		ii. 内部类的对象只能在与其外部类的对象相关联的情况下才能被创建(就像你应该看到的,内部类是非static 类时)。构建内部类对象时,需要一个指向其外部类对象的引用
	b. 如果你需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和
	this。
	c. 在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会暗暗
	地连接到建它的外部类对象上。但是,如果你创建的是嵌套类(静态内部类),那它
	就不需要对外部类对象的引用
	Parcel3 p = new Parcel3();
	// Must use instance of outer class
	// to create an instance of the inner class:
	Parcel3.Contents c = p.new Contents();
7.  函数式编程lambda
	a. 方法引用
		Java 8 方法引用没有历史包袱。方法引用组成:类名或对象名,后面跟:: 4,然后
		跟方法名称。
		// functional/MethodReferences.java
		import java.util.*;
		interface Callable { // [1]
		void call(String s);
		}
		class Describe {
		void show(String msg) { // [2]
		System.out.println(msg);
		}
		}
		public class MethodReferences {
		static void hello(String name) { // [3]
		System.out.println("Hello, " + name);
		}
		static class Description {
		String about;
		Description(String desc) { about = desc; }
		void help(String msg) { // [4]
		System.out.println(about + " " + msg);
		}
		}
		static class Helper {
		static void assist(String msg) { // [5]
		System.out.println(msg);
		}
		}
		public static void main(String[] args) {
		Describe d = new Describe();
		Callable c = d::show; // [6]
		c.call("call()"); // [7]
		c = MethodReferences::hello; // [8]
		c.call("Bob");
		c = new Description("valuable")::help; // [9]
		c.call("information");
		c = Helper::assist; // [10]
		c.call("Help!");
		}
		}
		输出结果:
		call()
		Hello, Bob
		valuable information
		Help!
		[1] 我们从单一方法接口开始(同样,你很快就会了解到这一点的重要性)。
		[2] show() 的签名(参数类型和返回类型)符合Callable 的call() 的签名。
		[3] hello() 也符合call() 的签名。
		[4] help() 也符合,它是静态内部类中的非静态方法。
		[5] assist() 是静态内部类中的静态方法。
		[6] 我们将Describe 对象的方法引用赋值给Callable ,它没有show() 方法,而是
		call() 方法。但是,Java 似乎接受用这个看似奇怪的赋值,因为方法引用符合Callable
		的call() 方法的签名。
		[7] 我们现在可以通过调用call() 来调用show(),因为Java 将call() 映射到
		show()。
		[8] 这是一个静态方法引用。
		[9] 这是[6] 的另一个版本:对已实例化对象的方法的引用,有时称为绑定方法引
		用。
		[10] 最后,获取静态内部类中静态方法的引用与[8] 中通过外部类引用相似。
		上例只是简短的介绍,我们很快就能看到方法引用的所有不同形式。
		
	b. 未绑定的方法引用
		// functional/UnboundMethodReference.java
		// 没有方法引用的对象
		class X {
		String f() { return "X::f()"; }
		}
		interface MakeString {
		String make();
		}
		interface TransformX {
		String transform(X x);
		}
		public class UnboundMethodReference {
		public static void main(String[] args) {
		// MakeString ms = X::f; // [1]
		TransformX sp = X::f;
		X x = new X();
		System.out.println(sp.transform(x)); // [2]
		System.out.println(x.f()); // 同等效果
		}
		}
		输出结果:
		X::f()
		X::f()
		截止目前,我们看到了与对应接口签名相同的方法引用。在[1],我们尝试把X 的
		f() 方法引用赋值给MakeString。结果即使make() 与f() 具有相同的签名,编译也
		会报“invalid method reference”(无效方法引用)错误。这是因为实际上还有另一个隐
		藏的参数:我们的老朋友this。你不能在没有X 对象的前提下调用f()。因此,X ::
		f 表示未绑定的方法引用,因为它尚未“绑定” 到对象。
		要解决这个问题,我们需要一个X 对象,所以我们的接口实际上需要一个额外的
		参数,如上例中的TransformX。如果将X :: f 赋值给TransformX,在Java 中是
		允许的。我们必须做第二个心理调整——使用未绑定的引用时,函数式方法的签名(接
		口中的单个方法)不再与方法引用的签名完全匹配。原因是:你需要一个对象来调用方
		法。
		[2] 的结果有点像脑筋急转弯。我拿到未绑定的方法引用, 并且调用它的
		transform() 方法,将一个X 类的对象传递给它,最后使得x.f() 以某种方式被调用。
		Java 知道它必须拿到第一个参数,该参数实际就是this,然后调用方法作用在它之上。
		如果你的方法有更多个参数,就以第一个参数接受this 的模式来处理。
	c. 构造函数引用
		构造函数引用
		你还可以捕获构造函数的引用,然后通过引用调用该构造函数。
		// functional/CtorReference.java
		class Dog {
		String name;
		int age = -1; // For "unknown"
		Dog() { name = "stray"; }
		Dog(String nm) { name = nm; }
		Dog(String nm, int yrs) { name = nm; age = yrs; }
		}
		interface MakeNoArgs {
		Dog make();
		}
		interface Make1Arg {
		Dog make(String nm);
		}
		interface Make2Args {
		Dog make(String nm, int age);
		}
		public class CtorReference {
		public static void main(String[] args) {
		MakeNoArgs mna = Dog::new; // [1]
		Make1Arg m1a = Dog::new; // [2]
		Make2Args m2a = Dog::new; // [3]
		Dog dn = mna.make();
		Dog d1 = m1a.make("Comet");
		Dog d2 = m2a.make("Ralph", 4);
		}
		}
		Dog 有三个构造函数,函数式接口内的make() 方法反映了构造函数参数列表
		(make() 方法名称可以不同)。
		注意我们如何对[1],[2] 和[3] 中的每一个使用Dog :: new。这三个构造函数只
		有一个相同名称::: new,但在每种情况下赋值给不同的接口,编译器可以从中知道具
		体使用哪个构造函数。
		编译器知道调用函数式方法(本例中为make())就相当于调用构造函数。
		
	d. 闭包
		i. 被Lambda 表达式引用的局部变量必须是final或者是等同final 效果的
		ii. 应用于对象引用的final 关键字仅表示不会重新赋值引用。它并不代表你不能修改对象本身。
		// functional/Closure8.java
		import java.util.*;
		import java.util.function.*;
		public class Closure8 {
		Supplier<List<Integer>> makeFun() {
		final List<Integer> ai = new ArrayList<>();
		ai.add(1);
		return () -> ai;
		}
		public static void main(String[] args) {
		Closure8 c7 = new Closure8();
		List<Integer>
		l1 = c7.makeFun().get(),
		l2 = c7.makeFun().get();
		System.out.println(l1);
		System.out.println(l2);
		l1.add(42);
		l2.add(96);
		System.out.println(l1);
		System.out.println(l2);
		}
		}
		输出结果:
		[1]
		[1]
		[1, 42]
		[1, 96]
		
		iii. 更改共享变量“不是线程安全的”
		iv. 函数编程
		Supplier---get()
		Comparator--compare()
		Consumer---accept()
		Function---apply()
		Predicate---test()
		v. 函数组合
			1. andThen(argument)
			2. compose(argument) 根据参数执行原始操作
			3. and(argument) 短路逻辑与原始谓词和参数谓词
			4. or(argument) 短路逻辑或原始谓词和参数谓词
			5. negate() 该谓词的逻辑否谓词
			下例使用了Function 里的compose() 和andThen()。代码示例:
			// functional/FunctionComposition.java
			import java.util.function.*;
			public class FunctionComposition {
			static Function<String, String>
			f1 = s -> {
			System.out.println(s);
			return s.replace('A', '_');
			},
			f2 = s -> s.substring(3),
			f3 = s -> s.toLowerCase(),
			f4 = f1.compose(f2).andThen(f3);
			public static void main(String[] args) {
			System.out.println(
			f4.apply("GO AFTER ALL AMBULANCES"));
			}
			}
			输出结果:
			AFTER ALL AMBULANCES
			_fter _ll _mbul_nces
			这里我们重点看正在创建的新函数f4。它调用apply() 的方式与常规几乎无异8。
			当f1 获得字符串时,它已经被f2 剥离了前三个字符。这是因为compose(f2)表
			示f2 的调用发生在f1 之前。
		
		vi. 柯里化(Currying)
		
		柯里化(Currying)的名称来自于其发明者之一Haskell Curry。他可能是计算机领
		域唯一姓氏和名字都命名过重要概念的人(另外就是Haskell 编程语言)。柯里化意为:
		将一个多参数的函数,转换为一系列单参数函数。
		// functional/CurryingAndPartials.java
		import java.util.function.*;
		public class CurryingAndPartials {
		// 未柯里化:
		static String uncurried(String a, String b) {
		return a + b;
		}
		public static void main(String[] args) {
		// 柯里化的函数:
		Function<String, Function<String, String>> sum =
		a -> b -> a + b; // [1]
		System.out.println(uncurried("Hi ", "Ho"));
		Function<String, String>
		hi = sum.apply("Hi "); // [2]
		System.out.println(hi.apply("Ho"));
		// 部分应用:
		Function<String, String> sumHi =
		sum.apply("Hup ");
		System.out.println(sumHi.apply("Ho"));
		System.out.println(sumHi.apply("Hey"));
		}
		}
		输出结果:
		Hi Ho
		Hi Ho
		Hup Ho
		Hup Hey
		[1] 这一连串的箭头很巧妙。注意,在函数接口声明中,第二个参数是另一个函数。
		[2] 柯里化的目的是能够通过提供单个参数来创建一个新函数,所以现在有了一个
		“带参函数” 和剩下的“自由函数”(free argument)。实际上,你从一个双参数函数开始,
		最后得到一个单参数函数。
		我们可以通过继续添加层级来柯里化一个三参数函数:
		// functional/Curry3Args.java
		import java.util.function.*;
		public class Curry3Args {
		public static void main(String[] args) {
		Function<String,
		Function<String,
		Function<String, String>>> sum =
		a -> b -> c -> a + b + c;
		Function<String,
		Function<String, String>> hi =
		sum.apply("Hi ");
		Function<String, String> ho =
		hi.apply("Ho ");
		System.out.println(ho.apply("Hup"));
		}
		}
		输出结果:
		Hi Ho Hup
		对于每一级的箭头级联(Arrow-cascading),你都会在类型声明周围包裹另一个
		Function。
posted @ 2023-08-08 17:05  HardisonDream  阅读(10)  评论(0)    收藏  举报