尚硅谷Java面向对象笔记Day08-Day16

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类图

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.提供重载的构造器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值