Day08
Java面向对象三条主线
- java类及类的成员:属性、方法、构造器;代码块、内部类
- 面向对象的三大特征:封装性、继承性、多态性、(抽象性)
- 其他关键字的使用:this/super/static/final/abstract…
面向过程(POP)和面向对象(OOP)的区别
二者都是一种思想。面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
程序员从面相过程的执行者,变成面向过程的指挥者。
对象的内存解析
我们将局部变量加载到VM Stack中,将new出来的结构(比如数组、对象)加载在堆空间中。补充,对象的属性(非static)加载在堆空间中。
方法区:类的加载信息、常量池、静态域
权限修饰符
常用的权限修饰符有:private、public、缺省、protected
默认初始化值
-
属性:类的属性,根据其类型,都有默认初始化值。
整形(byte、short、int、long),0
浮点型(float、double),0.0
字符型(char),0或’\0000’
布尔型(boolean),false引用数据类型(类、数组、接口),null
-
局部变量:没有默认初始化值,所以局部变量在使用前必须赋值。特别的,形参作为局部变量可以在调用时赋值
属性和局部变量的加载位置
- 属性:加载到堆空间中(static的加载到方法区)
- 局部变量:加载到栈空间
对象间传递的是地址值
...
//注意这里p1给p3的是地址值,故赋值后,p3p1指向同一个对象
Person p3 = p1;
p3.age=10;
System.out.println(p1.age);//10
...
Day09
对象数组的内存解析
匿名对象
方法的重载(overload)
同一个类中的同名方法(不同参数列表)
可变个数形参(variable number of arguments)
- 可传入0个参数
-
public void show(String ... strs){ //可变个数形参原本就是形参数组,故二者不能共存 for(int i=0;i<strs.length;i++){ System.out.println(strs[i]); } //数组作为形参和可变个数形参二者不可共存,不构成重载 // public void show(String[] strs){ // for(int i=0;i<strs.length;i++){ // System.out.println(strs[i]); // } }
- 可变个数形参必须声明在末尾
//错误示范
//public void show(String ... strs,int i){}
- 故最多只能声明一个可变个数形参
网红题
-
public class Test{ public static void main(String[] args){ int a = 10; int b = 10; method(a,b);//需要在method方法被调用之后,仅打印出a=100,b=200,请写出method方法的代码 System.out.println("a="+a); System.out.println("b="+b); } //代码编写处 //方法一: public static void method(int a,int b){ a = a*10; b = b*20; System.out.println(a); System.out.println(b); System.exit(0); } //方法二: public static void method(int a,int b){ PrintStream ps = new PrintStream(System.out){ @Override public void println(String x){ if("a=10".equals(x)){ x="a=100"; }else if("b=10".equals(x)){ x="b=200"; } super.println(x); } };//一行的末尾,必须加; //关键的一步,重新分配“标准”输出流。 System.setOut(ps); } }
- 定义一个int型数组:int[] arr = new int[]{12,3,3,34,56,77,432};让数组的每个位置上的值去除以首位置的元素,得到的结果,作为该位置上的新值。遍历新的数组。
//错误写法 for(int i=0;i<arr.length;i++){ arr[i] = arr[i]/arr[0]; } //正确写法1:倒序 for(inrt i = arrr.length-1;i>=0;i--){ arrr[i] = arr[i]/arr[0]; } //正确写法2 int temp = arr[0]; for(int i=0;i<arr.length;i++){ arr[i] = arr[i]/temp; }
-
public class ArrayPrintTest{ public static void main(String[] args){ int[] arr = new int[]{1,2,3}; System.out.println(arr);//地址值 char[] arr1 =new char[]{'a','b','c'}; System.out.println(arr1);//abc } }
Day10
高内聚、低耦合
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:仅对外暴露少量的方法用于使用
封装性的设计思想
隐藏对象内部的复杂性,只对外公开简单的方法和功能。便于外界调用,从而提高系统的可扩展性、可维护性。
四种权限修饰符
4种权限修饰符可以修饰4种类的内部结构:属性、方法、构造器、内部类
构造器
- 一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器。如需使用空参构造器,请自己声明。
赋值的顺序
默认初始化-显示初始化-构造器中赋值-通过对象点方法赋值
JavaBean
JavaBean是一种Java语言写成的可重用组件
- 类是公共的
- 有一个无参的公共的构造器(可以为反射创建对象提供便利)
- 有属性,且有对应的get/set方法
(默认构造器的权限和默认类的修饰符是一致的)
UML类图
this关键字
- 当前对象
- 可以用来修饰属性、方法、构造器
- this调用构造器,形式:this(形参列表);
- this调用构造器只能有一个 ,且在首行
import关键字
- 如果使用的类或接口是本包下定义的或是java.lang包下定义的,可省import结构
- 需要导入不同包下同名的类或接口,则至少有一个类要使用类的全类名
- import xxx.*仅代表导入xxx包内的所有结构,但不包括其子包下的结构
- import static xxx表示导入xxx包下的静态结构
Day11
单继承
java.lang.Object(顶级父类)
Day12
方法的重写(override/overwrite)
- 子类对父类同名同形参列表的方法的覆盖
- 子类重写的方法的权限修饰符不小于父类被重写方法的权限修饰符
特殊情况,子类不能重写父类中声明为private权限的方法
- 父类被重写方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
- 父类被重写的方法的返回值类型是A,则子类重写的方法的返回值类型可以是A或A的子类
- 父类被重写的方法的返回值类型是基本数据类型A,则子类重写的方法的返回值类型必须是A
- 子类和父类同名同参数的方法要么同为static,要么同非static,且非static才可能成为重写
构造器的首行默认调用super();
多态性:父类的引用指向子类的对象
- Person p2 = new Man();
当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法----虚拟方法调用(编译看父类(跳转跳父类),运行看子类重写的方法)
子类中定义了与父类同名同参数的方法,在多态的情况下,将此时父类的方法称为虚拟方法,父类根据赋给它的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。 - 属性的编译和运行都看左边父类
- 重载是指允许存在多个重名方法,而方法的参数不同。它们的调用地址在编译期就绑定了。这称为“早绑定”或“静态绑定”;
而多态直到方法调用的那一刻,解释运行器才会确定其调用的方法,称为“晚绑定”或“动态绑定” - 不是晚绑定就不是多态
Day13
向下转型
- 使用强转符
- 多态就是向上转型(很少这样说)
- 风险,可能转型失败ClassCastException
instanceof
- 为避免ClassCastException,向下转型前先instanceof
- a instanceof Man == true 则a instanceof Person == true
多态性的练习
package fun.wow808.java;
class Base{
int count = 10;
public void display() {
System.out.println(this.count);
}
}
class Sub extends Base{
//属性不具有多态性
int count = 20;
@Override
public void display() {
// TODO Auto-generated method stub
System.out.println(this.count);
}
}
public class FieldMethodTest {
public static void main(String[] args) {
Sub s = new Sub();
System.out.println(s.count);//20
s.display();//20
Base b = s;//多态
//"==",对于引用数据类型而言,比较的是两个引用数据类型的地址值
System.out.println(b == s);//true
System.out.println(b.count);//10,属性没有多态性
b.display();//多态的体现,20
}
}
多态是运行时行为
考查多态的面试题
package fun.wow808.java;
public class InterviewTest {
public static void main(String[] args) {
Base1 base = new Sub1();
base.add(1,2,3);//sub_0,多态
Sub1 sub1 = (Sub1)base;
sub1.add(1,2,3);//sub_1,向下转型后优先匹配不是可变形参的
}
}
class Base1{
public void add(int a,int... arr) {
System.out.println("base");
}
}
class Sub1 extends Base1{
//此时把可变形参和数组看作是同一个对待,因此是重写,是多态,
public void add(int a,int[] arr) {
System.out.println("sub_0");
}
public void add(int a, int b,int c) {
System.out.println("sub_1");
}
}
String中重写的Object的equals方法(了解)
public boolean equals(Object anObject){
if(this == anObject){
return ture;
}
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 false;
}
自定义类中重写的Object的equals方法(了解)
@Override
//自动生成
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Customer other = (Customer) obj;
//可能是Objects的equals是更通用于引用数据类型的方法,这是since 1.7的,同样用到多态,a.equals(b);
/*public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}*/
return age == other.age && Objects.equals(name, other.name);
}
String的初始化字符串存在常量池,故当用==比较时,也可相同,但是new的肯定不行
toString
- 当我们输出一个对象的引用时,我们实际上就是调用当前对象的toString方法
JUnit单元测试
1.添加@Test
2.创建Java类,进行测试,要求类是public的且提供公共的无参构造器
3.此类中可声明单元测试方法,public void(无参)
包装类
class Order{
boolean isMale;//基本数据类型,默认值false
Boolean isFemale;//引用数据类型,默认值null
}
since 5.0 自动装拆箱
基本数据类型和包装类与String的转换
- 包装类的Xxx xxx = parseXxx(String s);
- String s = String.valueOf(包装类);
- “+”
面试题
public void test(){
Object obj = true ? new Integer(1): new Double(2.0);
System.out.println(obj);//1.0,"?...:..."结构要求类型一致,故有自动类型提升
}
public viod test2(){
Integer i = new Integer(10);
Integer j = new Integer(10);
System.out.println(i == j);//false,引用类型比地址
Integer m = 1;
Integer n = 1;
System.out.println(m == n);//true
//源码在-128~127范围内统一赋好值了
Integer x = 128;
Integer y = 128;
System.out.println(x == y);//false
}
Day14
static关键字
- 可修饰属性、方法、代码块、内部类
- 静态变量随着类的加载而加载。静态变量的加载要早于对象的创建
- 由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中
- 静态方法不能调用非静态结构(想想生命周期,显而易见)
- 操作静态属性的方法设置为静态的
- 工具类的方法习惯上声明为静态的
方法区(类的加载信息、静态域、常量池)
static实例
class Circle{
private double radius;
private int id;//唯一标识圆的编号
private static int init = 1001;//用static保证编号的唯一性
private static int total;//用来记录圆的个数
public Circle(){
//利用构造器给ID赋值
id = init++;
total++;
}
//注意当有多个构造器时,用this()调用无参构造器,以保证逻辑的一致性,默认为super()
public Circle(double radius){
this();
//用this()替代下面两行
//id=init++;
//total++;
this.radius = radius;
}
}
设计模式(23种经典)
在大量实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式。
单例(Singleton)设计模式(需掌握手写)
保证在整个软件系统中,某个类只能存在一个对象实例
代码演示
//饿汉式
class Bank{
//私有化类的构造器
private Bank(){
}
//2.内部创建类的对象
//4.要求此对象也必须声明为静态的
private static Bank instance = new Bank();
//3.提供公共的静态方法,返回单例的对象
public static Bank getInstance(){
return instance;
}
}
//懒汉式
class Order{
//1.私有化类的构造器
private Order(){
}
//2.声明对象不创建(区分,啥时候用啥时候造是懒汉式)
private static Order instance = null;
//3.声明public、static的返回当前类对象的方法
public static Order getInstance(){
//4.判断是否创建过对象,以保证单例
if(instance == null){
instance = new Order();
}
return instance;
}
}
- 区分
饿汉式:
坏处:对象加载时间长
好处:饿汉式是线程安全的
懒汉式:
好处:延迟对象的创建
坏处:目前这种写法是线程不安全的 - 笔试尽量写饿汉式
- 单例模式的优点:减少了系统性能的开销
由于单例模式只生成一个实例,减少了系统性能的开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决
单例设计模式的应用场景
代码块
- 只分成静态代码块和非静态代码块
区别
1.非静态代码块随对象的创建而执行(可以为对象初始化属性)
2.静态代码块随着类的加载而执行,且只执行一次
由父及子,静态先行,代码块优先于构造器
main方法虽然是程序入口,但也是类中的静态方法,也遵循以上的顺序
赋值的顺序
1.默认初始化
2.显示初始化或代码块(按书写的先后顺序)
3.构造器中初始化
4.通过对象初始化
final关键字
- 可修饰类(不可继承)、方法(不可重写)、属性(不可修改,即常量)
- final修饰的属性可以显式赋值、代码块中初始化,构造器中初始化,不可以通过其他方法赋值,final修饰的属性在对象加载时必须确保被初始化
- final修饰局部变量,视为常量
尤其使用final修饰形参,则调用该方法时,给常量形参赋值一个实参后,则不可再次改变其值
全局常量(static final)
Day15
abstract
- 修饰类和方法
- 抽象类不能实例化
- 类一定有构造器,便于子类实例化
- 抽象方法只有方法的声明而没有方法体
- 包含抽象方法的类一定是抽象类,保证抽象方法不会被调用
- abstract不能用来修饰私有方法(原因无法重写)和静态方法(加static也不认为为重写)、final方法、final的类(final绝对不能重写,不能被继承)
抽象类的匿名子类(为了省事,只用一次)
假设public abstract Person(){
public abstract AA();
}
可以Person p = new Person{
@Override
public void AA();
}
匿名子类的匿名对象
假设public abstract Person(){
public abstract AA();
}
可以method(new Person{
@Override
public void AA();
});
模版方法设计模式
当功能内部的一部分是确定的,放在父类中;把不确定的暴露给子类去实现
父类一旦定义为抽象类,其内的非抽象方法一定尽量被子类使用,否则无用
抽象类数组是可以存在的,只要具体元素不能new抽象类就行
接口interface
- java单继承,但可以多实现
- 子父类一般是子类is a父类,接口一般是功能、规范、标准
- Java中接口和类是并列的结构
- 接口中可以定义全局常量(public static final)、抽象方法、静态方法(since 8)、默认方法(since 8)
- 接口中不能定义构造器
- 接口中的方法默认可省略,public abstract
- 接口的具体使用体现多态性
- 接口的本质是契约,标准,规范
接口与接口之间可以多继承
四种创建接口实现类的对象的代码演示
package fun.wow808.java;
public class USBTest {
public static void main(String[] args) {
Computer computer = new Computer();
//1.接口的非匿名实现类的非匿名对象
Flash falsh = new Flash();
computer.transferData(falsh);
//2.接口的非匿名实现类的匿名对象
computer.transferData(new Printer());
//3.接口的匿名实现类的非匿名对象
USB mouse = new USB(){
@Override
public void start() {
// TODO Auto-generated method stub
System.out.println("mouse开始传输");
}
@Override
public void stop() {
// TODO Auto-generated method stub
System.out.println("mouse停止传输");
}
};
computer.transferData(mouse);
//4.接口的匿名实现类的匿名对象
computer.transferData(new USB() {
@Override
public void start() {
// TODO Auto-generated method stub
System.out.println("mp3开始传输");
}
@Override
public void stop() {
// TODO Auto-generated method stub
System.out.println("mp3停止传输");
}
});
}
}
class Computer{
public void transferData(USB usb) {
usb.start();
System.out.println("computer传输细节若干");
usb.stop();
}
}
class Flash implements USB{
@Override
public void start() {
// TODO Auto-generated method stub
System.out.println("falsh开始传输");
}
@Override
public void stop() {
// TODO Auto-generated method stub
System.out.println("falsh停止传输");
}
}
class Printer implements USB{
@Override
public void start() {
// TODO Auto-generated method stub
System.out.println("Printer开始传输");
}
@Override
public void stop() {
// TODO Auto-generated method stub
System.out.println("Printer停止传输");
}
}
interface USB{
void start();
void stop();
}
代理模式
为其他对象提供一种代理以控制对这个对象的访问
/**
* 接口的应用:代理模式
* @author wow808
*
*/
public class NetWorkTest {
public static void main(String[] args) {
Server server = new Server();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browse();
}
}
interface NetWork{
public void browse();
}
//被代理类
class Server implements NetWork{
@Override
public void browse() {
System.out.println("真实的服务器访问网络!");
}
}
//代理类
class ProxyServer implements NetWork{
//注意这里不会定义
private NetWork netWork;
ProxyServer(NetWork netWork){
this.netWork = netWork;
}
public void check() {
System.out.println("联网之前的检查工作!");
}
@Override
public void browse() {
// TODO Auto-generated method stub
check();
netWork.browse();
}
}
工厂模式
实现了创建者和调用者的分离
排错面试题
interface Rollable中的变量是public static final的,因此不能在class Ball中重新赋值
当属性声明为Double类型时,可以调用包装类的方法compareTo()来比较大小
jdk8接口新特性
jdk7以前,借口里只能定义全局常量和抽象方法
jdk8以后,还可以定义静态方法和默认方法
接口中定义的静态方法,只能通过接口来调用
当一个类同时继承的与实现的同名同参数的方法,默认调用父类的方法:类优先原则
如果实现类实现了多个接口,且接口中有同名同参数的方法,则有接口冲突错误
interface.method()调用接口中静态方法
interface.super.method()调用接口中的默认方法
内部类
外部类.静态内部类 变量名 = new 外部类.静态内部类()
外部类.非静态内部类 变量名 = new 外部类对象.new 非静态内部类()
parameter//方法的形参
this.parameter//内部类的属性
类.this.parameter//外部类的属性
在局部内部类方法中,如果调用局部内部类所声明的方法中的局部变量,要求此局部变量声明为final
Day16
Error:jvm都无法解决的严重问题。如,JVM系统错误、资源耗尽等严重情况
Exception:其他因编程原因或偶然的外在因素导致的一般性问题,可以使用针对性代码进行处理。例如:空指针访问、试图读取不存在的文件、网络连接中断、数组角标越界
用异常避免大量的IF else检查
异常本质上也是程序在异常代码处生成的对象
try-catch
- try catch 只匹配一个,不会多个执行
- finally中是一定会执行的代码
像数据库连接、输入输出流、网络编程Socket等资源,JVM不能自动回收,我们需要自己手动的进行资源的释放。此时的资源释放,就要声明在finally中 - try-catch通常处理编译时异常,运行时异常就不处理了,改代码就是了
throws
- 使用throws一旦有异常,异常后的代码就不再执行
- throws把异常抛给了方法的调用者,并没有处理异常
- 子类重写的方法抛出的异常不大于父类被重写方法跑出的异常,子类重写方法可以小到没有,也可以大到等于
- 父类被重写方法没有用throws,则子类重写方法只能try-cacth
throw
自定义异常类
1.继承异常类
2.创建serialVersionUID
3.提供重载的构造器