java面向对象部分笔记

四种访问限制符:public、protected、默认、private

public class a {
	public static void main(String[] args) {
		Person p1 = new Person(); //有括号
	}
}

class Person {
	int age;
	String name;
}

类和内存对象的分配机制:

1. 栈:存放基本数据类型(局部变量)

2. 堆:存放对象(Cat cat、数组等)

3. 方法区:常量池(常量,如字符串)、类加载信息

4. 示意图Cat(name,age,price);


方法

public class a {
	public static void main(String[] args) {
		Person p1 = new Person(); //有括号
		p1.speak();//调用
	}
}

class Person {
	int age;
	String name;
	public void speak() {
		System.out.println("1");
	}
}

可变参数

public class a {
	public static void main(String[] args) {
		T t = new T();
		int nums[] = {1, 2, 3};
		System.out.println(t.sum(nums));
	}
}

class T {
	public int sum(int ...nums) {
		System.out.println("接受参数的个数 = " + nums.length);
		int res = 0;
		for(int i = 0; i < nums.length; i++) {
			res += nums[i];
		}
		return res;
	}
}

细节:可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后

class T {
	public void f1(String str, double ... nums) {
		
	}
}

 注意:一个形参列表只能出现一个可变参数

可变参数的本质是数组

可变参数的实参可以是数组


e.g.

//返回姓名和课程成绩
	public String shouwScore(String name, double ... scores) {
		double res = 0;
		for(int i = 0; i < scores.length; i++) sum += scores[i];
		return name + "有" + scores.length + "门课总成绩总分为" + res; // return String
	}

全局变量:也叫属性,作用域为整个类体

                 可以不赋值(可以使用默认值)

                作用域:可以被本类或其他类使用(通过对象调用,即创一个对象)

                可以加修饰符(public、private)

局部变量:一般指在成员方法中定义的变量

                必须赋值,否则会出错

                不可加修饰符

                作用域:只能在本类对应的方法中使用


构造器(完成对象的初始化,并不是创建对象)

1.构造器没有返回值

2.方法名必须和类名相同

3.在创建对象时,系统自动的调用该类的构造方法

4.构造器的修饰符可以是默认也可以是public、protected、private

5.一旦定义了自己的构造器,默认的构造器就被覆盖了

对象创建的流程分析

class Person {
	int age = 90;
	String name;
	Person(String n, int a){
		name = n;
		age = a;
	}
}
Person p = new("小倩", 20);

1.加载Person类信息(Person.class),只会加载一次。

2.在堆中分配空间

3.完成对象初始化(①默认初始化 age = 0 name = null ②显式初始化 age = 90,name = null

③构造器初始化 age = 20, name = 小倩)

4.对象在堆中的地址,返回给p


class Caculator{
	double num1;
	double num2;
	public Caculator(int num1, int num2) {
		this.num1 = num1;
		this.num2 = num2;
	}
	public Double div() {
		if(num2 == 0) {
			System.out.println("num2不能为0");
			return null; //null可以返回给Double类但不能返回给double
		}
		else {
			return num1 / num2;
		}
	}
}

包的三大作用:

①区分相同名字的类

②当类很多时,可以很好地管理类

③控制访问范围

包的基本语法:

package com.hspedu;

说明:

1.package关键字,表示打包

2.com.hspedu表示包名

包的命名:

只能包含数字、字母,不能用数字开头,不能是关键字或保留字

一般时com.公司名.项目名.业务模块名

常用的包:

java.lang //lang包是基本包,默认引入,不需要再引入

java.util //系统提供的工具包、工具类,使用Scanner

java.net   //网络包,网络开发

java.awt // 做java的界面开发,GUI

import java.util.*;

import java.uitl.Arrays;

Arrays.sort(arr); //排序工具

package的作用是声明当前类所在的包,需要放在类的最上面,之后才import...。

一个类中最多只有一句package


访问限制符

注意:

①修饰符可以修饰类中的属性,成员方法及类

②只有默认和public才能修饰类


继承

基本语法:class 子类 extends 父类  {

                }

父类又叫超类、基类

子类又叫派生类

public class a {
	String name;
	public void testing() {
		System.out.println("...");
	}
	public static void main(String[] args) {
	
	}
}

public class Graduates extends a {
	

}

注意:

私有属性不能在子类直接访问,要通过公共的方法去访问。

子类必须调用父亲的构造器,完成父类的初始化

当创建子类对象时,不管使用子类的哪个构造器,默认情况下会去调用父类的无参构造器。如果父类没有提供无参构造器,则必须在子类用super去指定使用父类的哪个构造器完成父类的初始化工作,否则,编译不会通过。

public class Sub extends a {
	public Sub(String name, int age) {
		super("hsp"); //指定调用哪个父类的构造器,是一个形式
		System.out.println("子类Sub(String name, int age)构造器被调用...");
		//父类a(String name)构造器被调用
	}
}

如果希望指定调用父类的某个构造器,则显示的调用:super(参数列表)

super在使用时必须放在构造器第一行,只能在构造器中使用。

super和this都只能放在构造器第一行,因此这两个方法不能放一个构造器中。

java中所有类都是Object类的子类

若想让A继承B和C可以A继承B,B继承C


super关键字

super代表父类的引用,用于访问父类的属性、方法、构造器

基本语法

1.访问父类的属性,但不能访问父类的private属性

    super.属性名(super.n1)

package work2;

public class A {
	int n1;
	public A(int n1) {
		this.n1 = n1;
	}
}

//
package work2;

public class B extends A{
	public B(int n1) {
		super(n1);
	}
	public void hi() {
		System.out.println(n1);
	}
}
//
package work2;

public class test {
	public static void main(String[] args) {
		B b = new B(1009);
		b.hi();
	}
}
//输出1009

2.访问父类的方法,不能访问父类的private方法

    super.方法名(参数列表)

    super.test1();

    super.test2();

3.访问父类的构造器

     super(参数列表) 只能放在构造器的第一句,只能出现一句

当子类中有和父类中的成员重名时,为了访问父类的成员,必须通过super,如果没有重名,使用super、this、直接访问是一样的效果。

若 this.cal( );

(1)先找本类,如果有,则调用。

(2)如果没有,则找父类(如果有,并且可以调用,则调用)

(3)如果父类没有,则继续找父亲的父亲...

注意:如果查找方法的过程中,找到了,但不能访问,则报错。

           如果查找方法中没有找到,则提示方法不存在。

super从父亲开始找


方法重写/覆盖

子类和父亲的某个方法的名称返回类型参数一样,则说子类覆盖了父亲的那个方法

注意:子类的返回类型和父类的返回类型一样,或者是父亲返回类型的子类

          父:public Object getInfo(){ } 

          子:public String getInfo(){ }

子类的方法不能缩小父类的访问权限

public > protected > 默认 > private

方法重写细节:

class AAA {
	public AAA m() {
		return null;
	}
}

class BBB extends AAA {
	public BBB m() {
		return null;
	}
}

其中:BBB是AAA的子类,m是方法重写


多态

函数重载、重写都是多态的体现

对象的多态(核心)

(1)一个 对象的编译类型和运行类型可以不一致

(2)编译类型在定义对象时,就确定了,不能改变

(3)运行类型是可以变化的

(4)编译类型看定义时 = 号的左边,运行类型看=号的右边

Animal animal = new Dog();//animal编译类型是Animal,运行类型是Dog
animal = new Cat(); //animal的运行类型变成了Cat,编译类仍然是Animal

多态的前提是:两个对象存在继承关系

多态的向上转型

(1)本质:父类的引用指向了子类的对象

(2)语法:父类类型 引用名 = new 子类类型();

(3)特点:编译类型看左边,运行类型看右边

可以调用父类中的所有成员(需遵守访问权限)

不能调用子类中特有成员(因为在编译阶段,能调用哪些成员,是由编译类型决定的)

最终运行效果看子类(运行类型)的具体实现,即调用子类(运行类型)开始查找方法

public class PolyDetail {
		//向上转型:父类的引用指向了子类的对象
		Animal animal = new Cat();
		Object obj = new Cat();
}

多态的向下转型

(1)语法:子类类型 引用名 = (子类类型)父类引用 //强制转换

(2)只能强转父类的引用,不能强转父类的对象

(3)要求父类的引用必须指向的是当前目标类型的对象

(4)可以调用子类类型的所有成员

Animal animal = new Cat();
Cat cat = (Cat) animal;
cat.catchMouse();

此时cat的编译类型是Cat,运行类型是Cat

instanceof 判断子类

public class PolyDetail {
	public static void main(String[] args) {
		Base base = new Sub();
		System.out.println(base.count); //看编译类型 10
		Sub sub = new Sub();
		System.out.println(sub.count); // 20
	}
}

class Base{
	int count = 10;//属性
}

class Sub extends Base {
	int count = 20;
}

属性不能重写,属性的值看编译类型

instanceof 比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的自类型

class Base {
	int count = 10;
	public void display() {
		System.out.println(this.count);
	}
}

class Sub extends Base {
	int count = 20;
	public void display() {
		System.out.println(this.count);
	}
}

public class PolyDetail{
	public static void main(String[] args) {
		Sub s = new Sub();
		System.out.println(s.count); //20
		s.display(); //20
		Base b = s; //base类型
		System.out.println(b == s); //T 判断地址是否相同 二者指向相同
		System.out.println(b.count); //b的编译类型为base
		b.display();//20
	}
}

java的动态绑定机制

1.调用对象时,该方法会和该对象的内存地址/运行类型绑定

2.当调用对象属性时,没有动态绑定机制,哪里声明,哪里调用。

class AA{
	public int i = 10;
	
	public int sum() {
		return getI() + 10;
	}
	public int sum1() {
		return i + 10;
	}
	public int getI() {
		return i;
	}
}

class BB extends AA{
	public int i = 20;
	
	public int sum() {
		return i + 20;
	}
	public int getI() {
		return i;
	}
	public int sum1() {
		return i + 10;
	}
}

public class PolyDetail{
	public static void main(String[] args) {
		AA a = new BB();
		System.out.println(a.sum());//40
		System.out.println(a.sum1());//30
	}
}

注释sum后结果为20,getI找到的i为20

for(int i = 0; i < persons.length; i++) {
	System.out.println(persons[i].say());//动态绑定机制
	if(persons[i] instanceof Student) {
		Student student = (Student)persons[i];//向下转型
		student.study();
	}
	else if(persons[i] instanceof Teacher) {
		Teacher teacher = (Teacher)persons[i];
		teacher.teach();
	}
	persons[i].teach();//不能执行,person没有teach
}

object类详解

==

==:既可以判断基本类型,也可以判断引用类型

==判断基本类型,判断值是否相等

==判断引用类型,判断地址是否相等,即判定是不是同一个对象

equals方法

equals只能判断引用类型,默认判断地址是否相等,子类往往重写该方法,比如Integer,String

Integer integer1 = new Integer(1000);
Integer integer2 = new Integer(1000);
System.out.println(integer1 == integer2); //false

String str1 = new String("hsp");
String str2 = new String("hsp");
System.out.println(str1 == str2); //false 看地址
System.out.println(ste1.equals(str2)); //true

重写equals方法

public boolean equals(Object obj) {
		if(this == obj) {
			return true;
		}
		if(obj instanceof Person) {
			Person p = (Person)obj;
			return this.name.equals(p.name) && this.age == p.age;
		}
		return false;
	}

hashCode方法

(1)提高具有哈希结构的容器的效率

(2)两个引用,如果指向的是同一个对象,则哈希值一样

(3)两个引用,如果指向的是不同对象,则哈希值不一样

(4)哈希值主要是根据地址号来的,但不能完全等价于地址

(5)有需要也可重写

System.out.println("aa.hashCode()="+aa.hashCode());

toString方法

默认返回:全类名+@+哈希值的十六进制

子类往往重写toString方法,用于返回对象的属性信息

当输出一个对象时,toString方法会被默认的调用

重写toString方法,输出对象的属性

快捷键alt + insert ->toString

finalize方法

1.当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作。

2.什么时候被回收,当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。

3.垃圾回收机制的调用,是由系统来决定,也可以通过System.gc()主动出发垃圾回收机制。


断点调试

F7(跳入)、F8(跳过)、Shift+F8(跳出)、F9(resume,执行到下一个断点)

F7:跳入方法内

F8:逐行执行代码

shift + F8:跳出方法


日期格式化

Date date = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH : mm");//用于日期格式化

类变量(静态变量)

static ...就可以在类的所有实例中共享(例如需要计数器时就可以使用 public static int count = 0)

类变量/静态变量可以通过类名访问

static类变量在类加载的时候就生成

定义语法:访问修饰符 static 数据类型 变量名

                  static 访问修饰符 数据类型 变量名

如何访问:类名.类变量名

                 对象名.类变量名(静态变量的访问修饰符的访问权限和范围和普通属性是一样的)

实例变量不能通过 类名.类变量名 方式访问

类变量在类加载的时候就初始化了,即使没有创建对象,只要类加载了就可以使用类变量。

类变量的生命周期是随类的加载开始,随着类的消亡而销毁。

实例:求累积学生的学费

class stu{
	private String name;
	private static double fee = 0;
	public stu (String name) {
		this.name = name;
	}
	public addfee(int fee) {
		this.fee += stu.fee;
	}
}

类方法

访问修饰符 static 数据返回类型 方法名(){ }

类方法的调用:类名.类方法名 或者 对象名.类方法名

类方法使用场景:当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率,如工具类中的方法utils Math类、Arrays类

e.g 

class cal{
	public static double sum(double n1, double n2) {
		return n1 + n1;
	}
}

注意

①类方法和普通方法都是随着类的加载而加载,将结构信息储存在方法区

②类方法中无this参数

③类方法可以通过类名调用,也可以通过对象名调用。普通方法需创建对象后调用。

④类方法中不允许使用和对象有关的关键字,比如this和super。普通方法可以

⑤类方法(静态方法)中,只能访问静态变量或静态方法,普通成员方法既可以访问普通变量(方法),也可以访问静态变量(方法)(必须遵守访问权限)

public class Test {
	static int count = 9;
	public void count() {
		System.out.println("count = " + (count ++ ));
	}
	public static void main(String[] args) {
		new Test().count(); // 9;
		new Test().count(); //10
		System.out.print(Test.count); //11;
	}	
}


main方法

1.main方法时虚拟机调用

2.java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public

3.java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static

4.该方法接受String类型的数组参数,该数组中保存执行java命令时传递给所允许的类的参数

5.java 执行的参数 参数1 参数2 参数3 args数组

public class homework02{
	public static void main(String[] args) {
		for(int i = 0; i < args.length; i++) {
			System.out.println("第" + (i + 1) + "个参数=" + args[i]);
		}
	}
}

提示:

1.在main方法中,可以直接调用main方法所在类的静态方法和静态属性。

2.对于非静态成员,必须创建该类的实例对象后,才能通过这个对象去访问类中的非静态成员。

public class main01 {
	private static String name = "stu";
	public static void hi() {
		System.out.println("main01的hi方法");
	}
	
	public static void main(String[] args) {
		//可以直接使用name
		//静态方法可以访问本类的静态成员
		System.out.println("name = " name);
		hi();
	}
}

代码块

代码块也叫初始化块,属于类的成员,类似于方法,将逻辑语句封装在方法体中,用{}包围起来。

代码块没有方法名,没有返回,没有参数,只有方法体,不能通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。

基本语法:

[ 修饰符 ]{

};    //;可省略

注意:

①修饰符可选写,只能写static

②使用static的叫静态代码块,没有static修饰的叫普通代码块

代码块的理解:

①相当于对构造器的补充机制,可以做初始化操作

②如果多个构造器都有重复的语句,可以抽取到初始块中,提高代码的重用性

③在创建对象时,不管调用哪个构造器,都会先调用代码块的内容。

class Movie{
	String name;
	double price;
	{
		System.out.println("电影开幕了");
	}
	public Movie(String name) {
		this.name = name;
	}
	
	public Movie(String name, double price) {
		this.name = name;
		this.price = name;
	}
}

注意:

1.static代码块,随着类的加载而执行,并且只会执行一次。

   普通代码块,每创建一个对象就执行。

2.类什么时候被加载?

①创建对象实例时。

②创建子类对象实例时,父类也会被加载(注意super)。

③使用类的静态成员时(静态属性、静态方法)

3.普通的代码块,在创建对象实例时,会被隐式的调用,被创建一次,就调用一次。

如果只是使用类的静态成员,普通代码块不会执行。

4.创建一个对象时,在一个类 调用顺序:

①调用静态代码块和静态属性的初始化(按顺序)

②调用普通代码块和普通属性的初始化

③调用构造方法

5.创建一个子类(继承关系),调用顺序如下:
①父类的静态代码块和静态属性

②子类的静态代码块和静态属性

③父类的普通代码块和普通属性

④父类的构造方法

⑤子类的普通代码块和普通属性

⑥子类的构造器

注意:静态代码块只能调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。


单例设计模式

步骤:

1.构造器私有化

2.类的内部创造对象

3.向外提供一个静态的公共方法,getInstance

4.代码实现

饿汉式:

class GirlFriend {
	private String name;
	
	private static GirlFriend gf = new GirlFriend("z");
	
	private GirlFriend(String name) {
		this.name = name;
	}
	public static GirlFriend getInstance() {
		return gf;
	}
}

懒汉式

class GirlFriend {
	//为了能在静态方法中返回gf对象,需要将其修饰为static,static不创建对象情况下使用。
	private String name;

	private static GirlFriend gf;
	
	private GirlFriend(String name) {
		this.name = name;
	}
	public static GirlFriend getInstance() {
		if(gf == null) gf = new GirlFriend("z");
		return gf;
	}
}

对比:

1.主要区别在于创建对象的时机不同,饿汉在类加载就创建了对象实例,懒汉式在使用时才创建。

2.饿汉式不存在线程安全为,懒汉式存在线程安全问题

3.饿汉式存在浪费资源的可能。


final关键字

可以修饰类、属性、方法、局部变量

使用情况:

①当不希望类被继承

②当不希望父类的某个方法被子类覆盖、重写

③当不希望类的某个属性值被修改

④当不希望某个局部变量被修改

final class A

public final void hi() { }

不希望类的某个属性被修改public final double a = 0.0;

不希望某个局部变量被修改 public double TAX_RATE = 0.08;

注意:

①final修饰的属性又叫常量,必须赋初值,并且以后不能修改,赋值可以加载如下位置之一

1.定义时        2.在构造器中         3.在代码块中

②如果final修饰的属性是静态的,则初始化的位置只能是定义时或在静态代码块内,不能在构造器中赋值。

③final类不能继承,但是可以实例化对象

⑤如果类不是final类,但是含有final方法,则该方法虽然不能被重写,但是可以被继承

⑥一般某个类已经是final类了,就没必要将方法修饰成final方法

⑦final不能修饰构造器

⑧final和static往往搭配使用,不会导致类加载,底层编译器做了优化处理,效率更高。

public final static int num = 1000;

在main输出(XX.num)不会导致XX类的加载。

⑨包装类(Integer,Double,Float,Boolean等都是final),String也是final类

注:

可以public int add(final int x) { x ++;} //错误x不能被修改


抽象类

用abstract关键词修饰一个类时,该类叫抽象类

访问修饰符 abstract 类名{ }

用abstract修饰一个方法时,这个方法就是抽象方法

访问修饰符 abstract 方法名(参数列表); 不能有方法体

注意:

抽象类不能实例化

抽象类不一定要有抽象方法

一旦有抽象方法,则该类必须为抽象类

抽象类可以有任意成员,如:非抽象方法、构造器、静态属性等

如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类

抽象方法不能使用private、final、static修饰

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值