疯狂java讲义第六章笔记

面向对象(下)

6.1 java8增强的包装类

int Integer
char Character
其他的都是直接首字母变大写
可以自动装箱,自动拆箱。
如果int想变成Integer,直接赋值给一个Integer 变量就行。
如果Integer想变成int,直接赋值给一个int变量就行。

基本类型和字符串之间的转换方法

  1. 字符串转换成基本类型
    int i=Integer.parseInt(str);
    或者
    int i=new Integer(str);
  2. 基本类型转换成字符串
    String flStr=String.valueOf(float变量);
    或者
    String flStr=float变量+“”;

包装类比较大小

  1. 如果直接给integer数字,如果数字在-128-127之间,则两个数字相等,包装类相等。
  2. 如果用new integer(2)赋值,则必须两个包装类指向同一个对象才相等。
  3. 有一个Integer.compare(a,b)可以直接用来比较包装类大小.
    a>b 返回1
    a=b 返回0
    a

6.2 处理对象

6.2.1 打印对象和toString方法

toString方法
toString () 是Object类里面的一个实例方法,所有对象都具有这个方法。
系统自带的tostring“类名+@+hashcode”
可以自己重写这个方法。

6.2.2 ==和equals方法

“==”

  1. 对于基本类型的数值类型(包括char),只要两个变量的值相等,返回true。
  2. 对于引用类型,必须指向同一个对象,才返回true。
    注意:“==“不能用于比较没有父子关系的两个对象。
    ”hello“直接量和new String (“hello”)区别
    直接使用hello这种可以在编译时候计算出来的字符串值,jvm会用常量池来管理。jvm会保证相同的字符串直接量只有一个,不会产生多个副本。
    第二种,jvm会先用常量池来管理直接量,再调用string构造器来创建 i 个新的string对象。新创建的对象保存在堆中

equals()

equals()方法可以用来判断字符串的内容是否相等。
但是当用于对象时,仍然必须是指向同一个对象才能够返回true。
一般需要重写equals()。

  1. 首先判断是否是同一个对象
  2. 如果不是同一个对象,在判断是否是同一个类型
  3. 如果是的话,把object转化为目标类型,采用equals方法比较内容。

6.3 类成员

6.3.1 理解类成员

类成员就是用static修饰的成员变量,方法,初始化块,内部类的统称。能通过对象访问这些类成员。即使对象是null 。类成员不能访问实例成员,因为类成员的作用域更大,可能类成员还存在,但是成员变量已经不存在了,所以不能够访问实例成员。

6.3.2 单例类

一个类始终只能创建一个实例,称为单例类。
如果不想让别的类轻易的创建该类的对象,就需要把类的构造函数设置成private,但是这个时候就需要有一个方法来创建一个对象,由于使用这个方法的时候还没有对象,因此需要给方法是static的。
同时。为了满足只能创建一个对象,则必须把已经创建的对象保存起来,每次创建对象之前都检查一下是否只有一个对象。由于存储对象的成员变量需要通过上面的static方法调用,因此需要设置为static。

package demo6;

public class Singleton {
    //定义一个类变量用来保存创建出来的对象
    private static Singleton instance;
    private Singleton(){}
    //定义一个能够返回对象的方法
    public static Singleton getSingleton()
    {
        if(instance==null)
        {
            instance=new Singleton();
        }
        return instance;
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Singleton s1=Singleton.getSingleton();
        Singleton s2=Singleton.getSingleton();
        System.out.print(s1==s2);

    }

}

6.4 final修饰符

final修饰变量时候表示该变量一旦获得了初始值,就无法再改变。

6.4.1 final成员变量

类变量:在静态初始化块或者声明该变量时初始化
实例变量:在普通初始化块,或者声明该变量时候,或者构造器。如果已经在普通初始化块赋值,则不可以再在构造器中赋值。
注意⚠:普通方法不能访问final修饰的成员变量。
final修饰的成员变量必须程序员自己显示初始化,系统不会默认赋值。

6.4.2 final局部变量

因为系统不会给局部变量初始化,因此在用final修饰的局部变量不一定非由程序员显示初始化。
方法中的形参不能够在方法里面初始化,因为形参的初始化是在被调用的时候由实参传入的。

6.4.3 final修饰基本类型变量和引用类型变量的区别

final修饰基本类型变量,就不能更改值了。如果是引用类型,则只要不改变地址就行,里面的内容可以随意

package demo6;

import java.util.Arrays;

class Person1
{
    private int age;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Person1() {}
    public Person1(int age)
    {
        this.age=age;
    }
}


public class FinalReferenceTest {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //可以无限的更改数组里面的内容,但是不能够更改数组的地址
        final int[] iArr={3,4,5,6};
        iArr[2]=19;
        System.out.print(Arrays.toString(iArr));
        Arrays.sort(iArr);
        System.out.println(Arrays.toString(iArr));
        //iArr=null;
        Person1 p1=new Person1();
        p1.setAge(7);
        //这里竟然可以更改,,,,,不懂不懂
        p1=null;
        System.out.print(iArr);
        

    }

}

6.4.4 可执行“宏替换”的final变量

变量满足三个条件,则变量相当于一个直接量

  1. final修饰
  2. 在定义的时候指定了初始值(只有在定义的时候赋值才有这种效果)
  3. 值可以在编译的时候确定下来

6.4.5 final 方法

final方法不能够被重写。如果父类的方法不希望子类重写,只要加上final 就好。
但是父类的private 是不会被子类继承的,因此也不会有重写这个说法。因此如果父类的private方法被final了,子类仍然可以写一个一样的方法。

6.4.6 final类

不能有子类的类

6.4.7 不可变类

不可变类是创建该类的实例后,实例变量不能够更改。
创建自定义的不可变类方法:
1,类的成员变量用private和final修饰
2,提供带参数的构造函数,用于根据传入参数来初始化类的成员变量
3,该类仅有getter
4,重新定义equals()和hashcode()

package demo6;

public class Address {
    private final String detail;
    private final String postCode;
    public Address()
    {
        this.detail="";
        this.postCode="";
    }
    public Address(String detail,String postCode)
    {
        this.detail=detail;
        this.postCode=postCode;
    }
    public String getDetail()
    {
        return detail;
    }
    public String getPostCode()
    {
        return postCode;
    }
    public boolean equals(Object obj)
    {
        if(obj==this)
        {
            return true;
        }
        if(obj!=null&&obj.getClass().equals(Address.class))
        {
            Address AddObj=(Address)obj;
            if(AddObj.getDetail().equals(this.getDetail()))
            {
                return true;
            }
        }
        return false;
    }
    

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        

    }

}

当创建不可变类的时候,如果成员变量里面有引用类型,则很可能创建出一个可变类,因为成员变量的内容可以更改。必须采用一些其他的方法,才能创建真正的不可变类。

6.4.8 缓存实例的不可变类

缓存实例的不可变类,是因为有的时候一个对象的某个成员被多次引用,为了节省开销,可以把它缓存起来。下边是把它缓存在数组里面,如果缓存里面已经有了,就直接返回实例,如果没有,就新建实例加进去。

package demo6;
//这个类主要是弄一个数组,然后缓存string数据
class CacheInnutale
{
    private static int MAX_SIZE;
    private static CacheInnutale[] cache=new CacheInnutale[MAX_SIZE];
    //pos为什么要是static
    private static int pos=0;
    private final String name;
    public String getName() {
        return name;
    }
    private CacheInnutale(String name)
    {
        this.name=name;
    }
    // 使用数组缓存已有的实例,并且记录缓存的位置
    public static CacheInnutale valueOf(String name)
    {
        //遍历已经缓存的对象,如果有相同的,直接返回缓存的实例
        for(int i=0;i

6.5 抽象类

抽象方法是只有方法的签名,没有方法的实现

6.5.1 抽象方法和抽象类

抽象方法和抽象类必须使用abstract修饰,有抽象方法的类一定是抽象类。
规则:

  1. 抽象方法不能有方法体
  2. 抽象类不能够被实例化
  3. 抽象类的构造函数不能够用来创造实例,主要用于被子类调用
  4. 含有抽象方法的类(包括直接定义了一个抽象方法;继承了一个抽象父类,但是没有完全实例化父类包含的抽象类;或是实现了一个接口,但是没有完全实例化接口包含的抽象方法)
public class Triangle extends Shape{
    //定义三角形的三边
    private double a;
    private double b;
    private double c;
    public Triangle(String color,double a,double b,double c)
    {
        super(color);
        this.sideSides(a,b,c);
    }
    public void sideSides(double a,double b,double c)
    {
        if(a+b<=c||a+c<=b||c+b<=a)
        {
            System.out.print("两边之和必须大于第三边");
            return ;
        }
        this.a=a;
        this.b=b;
        this.c=c;
        
    }
    //重写计算周长的方法
    public double calPerimeter()
    {
        return a+b+c;
    }
    public String getType()
    {
        return "三角形";
    }
    public static void main (String[] args)
    {
        //如果不用抽象类的话,s1是不能够直接调用gettype方法的。
         
        Shape s1=new Triangle("yello", 3, 4,5);
        System.out.println(s1.getType());
        System.out.print(s1.calPerimeter());
    }
    

}

abstract与final不能同时出现:abstract类表示只能被继承,但是final类不能被继承。
abstract和static一般不能同时修饰方法:static修饰的方法表示属于类的,可以通过类来访问。但是如果同时也是abstract的话,则没有方法体。这就没办法调用。(内部类除外)
abstract和private不能同时修饰方法:private修饰的方法是不会被继承的。但是abstract需要继承。

6.5.2 抽象类的作用

作为子类的模版。

6.6 java8改进的接口

将抽象类“抽象”到极致,只包含抽象方法。就是接口。

6.6.1 接口的概念

接口定义的是多个类共同的公共行为规范,接口里通常是定义一组公共方法。
接口不提供任何实现,体现的是实现和规范相分离的设计哲学。

6.6.2 java8中接口的定义

关键词:interface
修饰符:public 或者省略,省略是默认default
一个接口可以继承多个接口

由于接口定义的是一种规范,因此接口没有构造器和初始化块,接口可以包含成员变量(静态常量),静态方法和抽象方法以及默认方法。都必须是public

  1. 静态常量:无论是否有修饰符,都是public static final的,需要在定义的时候指定默认值。可以跨包访问,但是因为是final,不能修改值。
  2. 接口里面的普通方法只能是public的抽象abstract方法
  3. 在接口定义默认方法,需要使用default修饰(默认都是public修饰,不能static修饰)
  4. 在接口定义类方法,需要使用static(默认都是public ,不能用default修饰)
  5. java里面最多定义一个public的接口,如果有public的接口,则主文件名和接口名相同

6.6.3 接口的继承

支持多继承,以逗号分格

6.6.4 使用接口

implements实现多个接口。如果一个类继承了一个接口,就必须把里面的抽象方法都实现,否则就必须定义成抽象类。
实现接口的方法时必须使用public
模拟多继承:接口名 引用变量名=new 类(初始化参数),类就可以访问接口的方法以及自己的方法。类的方法就变的很多。

package demo6;
//定义一个product接口
interface Product
{
    int getProductTime();
}
public class Printer implements Product , Output{
    private String[] printData=new String[MAX_CACHE_LINE];
    //记录当前需打印的作业数
    private int dataNum=0;
    public void out()
    {
        //只要还有作业就继续打印
        while(dataNum>0)
        {
            System.out.println(printData[0]);
            System.arraycopy(printData, 1, printData, 0, --dataNum);
        }
    }
    public void getData(String msg)
    {
        if(dataNum>=MAX_CACHE_LINE)
        {
            System.out.println("输出队列已经满了。添加失败");
        }else {
            printData[dataNum++]=msg;
        }
    }
    public int getProductTime()
    {
        return 45;
    }
    
    

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //创建一个printer对象,当成output使用
        Output o=new Printer();
        o.getData("疯狂jav");
        o.getData("疯狂jaba讲义");
        o.out();
        o.getData("疯狂安卓讲义");
        o.getData("疯狂安卓");
        o.out();
    }

}

6.6.5 接口和抽象类

接口:体现一种规范,对于接口的实现者,接口定义了必须实现那些服务;对于接口的调用者,规定了调用者可以调用哪些方法。
抽象类:体现一种模版的设计,他是没有设计完的一个类,需要子类补充将它完成。

6.6.6 面向接口编程

  1. 简单的工厂模式
    不太懂啊
package demo6;

public class Computer {
    private Output out;
    public Computer(Output out)
    {
        this.out=out;
    }
    //定义一个模拟获得字符串的方法
    public void keyIn(String msg)
    {
        out.getData(msg);
    }
    public void print()
    {
        out.out();
    }

}


package demo6;

public class OutputFactory {
    public Output getOutput()
    {
        return new  Printer();
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        OutputFactory oF=new OutputFactory();
        Computer c=new Computer(oF.getOutput());
        c.keyIn("java");
        c.keyIn("ilovayou");
        c.print();

    }

}

2.命令模式

定义一个接口,接口里面定义一个抽象的方法,作用在一个数组上。然后实例化这个接口,可以实例化多个,每个都是作用在数组上的一种方法,
???????????

6.7 内部类

定义在其他类内部的类叫做内部类。
包含内部类的类叫做外部类。
内部类的作用:

  1. 提供了更好的封装性,不允许同一个包中的其他类访问。
  2. 内部类可以直接访问外部类的私有数据。因为内部类可以当作外部类成员。外部类不可以访问内部类的实现细节
  3. 匿名内部类适合用于创建只需要一次使用的类。
    内部类外部类区别:
  4. 内部类比外部类多3个修饰符,private protected static
  5. 非静态内部类不能有静态成员

6.7.1 非静态内部类

在外部类里面使用非静态内部类时,和使用普通的类没有什么区别。非静态内部类可以访问外部类的pirvate成员,因为非静态内部类的对象里面,保存了一个外部类对象的引用。
外部类成员变量,内部类成员变量,内部类里面方法的局部变量可以同名,用this区分。
外部类不能够访问非晶态内部类的成员,必须创建一个对象才行。new inner(),,,因为外部类存在的时候,内部类不一定存在,但是内部类存在,外部类一定存在。
不允许在外部类的静态成员中直接使用非静态内部类
不允许在非静态内部类里面定义静态成员。

6.7.2 静态内部类

用static修饰的内部类叫做静态内部类。这个内部类属于外部类本身,不属于外部类的任何一个对象。
外部类不能够用statc修饰,因为外部类的上一级是包,所以没有类的概念,但是内部类的上一层是外部类,所以可以用static修饰。
静态内部类可以有静态成员和非静态成员,静态内部类不能够访问外部类的实例成员,只能访问类成员。(因为静态内部类里面只有外部类的引用,没有外部类对象的引用)
外部类依旧不能访问内部类的成员,但是可以通过类名或者对象访问内部类成员对象。
java允许定义接口内部类,默认是public static修饰。也就是说,接口的内部类一定是静态内部类。

6.7.3 使用内部类

在外部类内部使用内部类
基本上与平常使用普通类没有区别。唯一的区别是不要在外部类的静态成员中使用非静态内部类。

在外部类以外使用非静态内部类
在外部类以外的地方定义内部类变量的语法:
outclassname.innerclassname name;
创建非静态内部类对象(非静态内部类的构造器必须用外部类对象调用)
outerInstance.new InnerConstructor()

class Out
{
    class In
    {
        public In(String msg)
        {
            System.out.println(msg);
        }
    }
}

public class CreateInnerInstance {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //使用outclass.innerclass的形式定义内部类变量
        Out.In in;
        //创建外部类对象
        Out out=new Out();
        //通过外部类对象创建内部类对象
        in=out.new In("测试出错");
        

    }

}

1.创建非静态内部类的子类

package demo6;

public class SubClass extends Out.In {
    public SubClass(Out out)
    {
        out.super("hello");
    }

}
  1. 在外部类以外使用静态内部类
    new outclass.innerConstruction

可以看出无论是静态内部类还是非静态内部类,声明变量的方法都是一样的。区别在于创建内部类对象。优先考虑静态内部类。

6.7.4 局部内部类

放在方法里面的内部类
一般不用

6.7.5 java8改进的匿名内部类

匿名内部类适合创建只需要一次使用的类。创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用。
匿名内部类必须继承一个父类,或者实现一个接口,但是最多只能是一个。
匿名内部类的两条规则:

  1. 不能是抽象类,因为抽象类不能被实例化,但是匿名内部类创建的时候就要创建对象
  2. 不能定义构造器,因为匿名内部类没有类名。
    最常用的创建匿名内部类是需要创建某个接口类型的对象。
    局部变量被匿名内部类访问,局部变量相当于自动加了final修饰。因此不能够再被修改。

6.8 java8新增的lambda表达式

6.8.1 lambda表达式入门

lambda表达式支持代码作为方法参数,可以创建只有一个抽象方法的接口的实例。
lambda表达式由形参列表 ->和方法体组成

6.8.2 lambda表达式和函数式接口

lambda表达式的目标类型必须是函数式接口
函数式接口代表只包含一个抽象方法的接口。函数式接口可以包含多个默认方法,类方法,但只能有一个抽象方法。
java8为函数式接口加了@FunctionalInterface注解 用于告诉编译器更严格的检查

6.8.3 方法引用和构造器引用

如果代码块只有一行代码,则可以在lambda表达式中使用方法引用和构造引用。
引用类方法 类名::类方法
引用特定对象的实力方法 特定对象::实例方法
引用某类对象的实例方法 类名::实例方法
引用构造器 类名::new

6.8.4 lambda表达式和匿名内部类的联系和区别

lambda表达式是匿名内部类的一种简化。
相同点:
都可以直接访问“effectively final”的局部变量,以及外部类的成员变量
所创建的对象可以直接调用从接口中继承的默认方法
区别
匿名内部类可以为任意接口创建实例,而lambda表达式必须是函数式接口
匿名内部类可以为抽象类甚至普通类创建实例。
匿名内部类的方法体可以调用接口中定义的默认方法,但是lambda不可以,它只有对象可以调用。

6.9 枚举类

枚举类是指实例有限而且固定的类

6.9.2 枚举类入门

枚举类是一种特殊的类,可以有自己的成员变量,方法,可以实现一个或者多个接口。

  1. 默认继承java.lang.Enum类,不能显式继承其他父类。
  2. 使用Enum定义,非抽象的枚举类默认是final修饰,不能派生子类
  3. 构造器为private
  4. 所有实例必须在第一行显式列出,系统默认加上public static final
  5. 如果需要使用某个实例,用EnumClass.variable

6.9.3 枚举类的成员变量,方法和构造器

枚举类的成员变量最好都使用private final修饰
如果构造函数有参数,则在第一行列出实例的时候,要写上参数。
枚举类的实例只能是枚举值,不能随意通过new来创建。???

6.9.4 实现接口的枚举类

与普通类完全一样,也需要实现该接口所包含的方法
如果不同的枚举值想在调用一个方法时呈现不同的行为方式,则可以让每个枚举值分别实现该方法,这个时候,不是在创建枚举类的实例,而是创建匿名子类的实例。

6.9.5 包含抽象方法的枚举类

每个枚举值都必须为抽象方法提供实现,否则报错。

6.10 对象和垃圾回收

6.10.1 对象在内存中的状态

可达状态
可恢复状态
不可达状态

6.10.2 强制垃圾回收

System.gc()
Runtime.getRuntime().gc()

6.10.3 finalize方法

6.11 修饰符的适用范围

6.12 使用JAR文件

你可能感兴趣的:(疯狂java讲义第六章笔记)