面向对象总结

面向对象**

类,对象,引用

类是具有相同属性和行为的对象的集合。
类定义了该类型对象的数据结构, 称之为“成员变量”,同时也定义了一些可以被调用的功能,称之
为“方法”。
类是用于构建对象的模板,对象的实质就是内存中的一块存储区域,其数据结构由定义它的类来决
定。
定义类
类的成员变量
类的成员方法

public class Point{
    public static Point point;
    //自定义了一个用于描述点类型:Point
        int x;//横坐标
        int y;//纵坐标
        //方法能做什么
        public void up() {

              y++;
            //public公开的方法  void表示无返回值  up表示无参数y++;//纵坐标+1
        }public void up(int y){
            this.y=y;

    }

其中int x是成员变量
public void up(){
}是成员方法

对象

当一个类的定义存在后, 可以使用 new 运算符创建该类的对象。
对象创建的过程一般称为类的实例化
在这里插入图片描述
成员变量的初始化
对象创建之后,其成员变量可以按照默认的方式初始化,对象成员具有默认值。
成员变量的默认初始化值规则
在这里插入图片描述
即在没有构造有参函数和赋值的情况下,系统会默认为空参,而且会自动构造空参来赋值,只是没有显示出来。
如果在构造出来有参函数的情况下,他是不会自动构造无参函数。需要我们手动构造无参函数。
成员变量的调用
成员变量的调用,可以根据某个对象的引用,找到成员变量,然后使用成员变量。


```java
// 1. 创建一个汽车
Car car = new Car() ; // 创建的对象,赋值给引用类型的变量。
// 2. 给汽车的属性赋值
car.pinPai = "BYD宋";
car.color = "红色";
car.faDongJi = "byd发动机";
car.count = 7 ;
成员方法的调用
方法的调用必须通过某个对象的引用。
当通过么对象的引用调用方法时,方法中涉及的成员变量就是该对象的成员变量。

```java
Person p1 = new Person();
 p1.eat();
 p1.sayHello();
 p1.driver();

引用类型

除8种基本数据类型之前,用类名(接口,数组)声明的变量称为引用类型变量,简称引用。
引用类型变量中存储的是某个对象在内存中的地址信息。
引用的功能在于访问对象
引用类型变量声明语法规则:
类名 引用类型变量名:
eg:Person pn=new Person

JVM内存结构

方法区

该区间用于存放类的信息。java程序运行时候,首先会通过类加载器载入类文件的字节码文件,经
过解析后将其装入方法区。类的各种信息都在方法区保存。
在这里插入图片描述

栈内存区

栈用于存放程序运行过程中的局部变量。
引用类型的变量p ,存储在栈内存中。
在这里插入图片描述

堆内存区

jvm会在其内存空间开一个称为“堆”的存储空间,这部分空间用于存储使用new关键字创建的对
象。
创建了一个Person对象,存储在堆内存中
在这里插入图片描述

方法的重载

在java语言中,允许多个方法的名称相同,但参数列表不同,称之为方法的重载(overload)。
编译器在编译时,会根据其参数的不同,绑定到不同的方法
构造函数的时候也是方法的重载

public void sum(int a,int b){a+b;}
public void sum (double a,doule b){a+b;}
pubilc void sum (String a,String b){a+b:}

this

在方法中可以通过this关键字表示调用该方法的对象。
通常在类中使用this区分成员变量和参数,如果没有歧义,可以省略this。
在这里插入图片描述

null

引用类型变量用于存放对象的地址,可以给引用类型赋值为null,表示不指向任何对象。
如果某个引用类型变量为null的时候,不能访问对象,否则抛出空指针异常。
###构造函数
6.1

定义构造方法

构造方法是在类中定义的方法(每个类都有构造方法):
— 构造方法的名称必须和类名相同.
— 构造方法没有返回值,但也不能写void.
在java语言中可以通过构造方法实现对象成员变量初始化。
构造方法重载
为了使用方便对一个类定义多个构造方法,这些构造方法彼此参数不同,称为构造方法的重载。
创建对象时,java编译器会根据不同的参数,选择不同的构造函数。

继承

extends关键字可以实现类的继承
子类(sub class) 可以继承父类(super class)的成员变量及成员方法。同时也可以定义自己的
成员变量和成员方法。
java语言不支持多继承,一个类只能继承一个父类。 但一个父类可以有多个子类。`

package oopday2;
import java.util.Date;
// 动物类型: 公共的成员变量 , 公共的成员方法
// 颜色 , 生日, 性别 , 脚的数量 , 叫 , 吃 , 跑
// 鸡类 : 飞 ,
// 狗类 : 看门 ,
// ** java规定,一个java文件只能有一个公开类 , 并且这个公开类的名字必须和java文件名相
同。
public class Animal {
String color ;// 颜色
Date birth ;// 生日
String sex ;// 性别
int count ;// 脚的数量
public void sing(String sing){
System.out.println("唱:" +sing);
}
public void eat(String food){
System.out.println("吃:" + food);
}
public void run(){
System.out.println("到处跑");
}
}
/*Chicken 这个类型,只有一个成员方法。
class Chicken{
public void fly(){
System.out.println("飞....");
}
}
*/
// Chicken 继承了Animal中的所有成员变量和成员方法, 同时有自己独有的fly方法。
class Chicken extends Animal{
public void fly(){
System.out.println("飞......");
}
}
// Dog 继承了Animal中的所有成员变量和成员方法, 同时有自己独有的seeDoor方法。
class Dog extends Animal{
public void seeDoor(){
System.out.println("保护家园.......");
}
}

###向上造型
一个子类的对象可以向上造型为父类的类型
Father f = new Sun();
java编译器编译的时候根据父类型检查调用的成员变量和成员方法是否匹配

// 3. 向上造型 : 子类对象,赋值给父类的引用
Animal dog = new Dog() ;//
dog.birth = new Date();
dog.color = "黄色";
dog.count = 4 ;
dog.sex = "女";
dog.sing("汪汪。。。。");
dog.eat("狗粮......");
dog.run();
// dog.seeDoor() ;// 编译错误: 在编译的时候, dog引用是按引用的类型Animal使
用。 Animal没有seeDoor的方法
// 在运行的时候, dog引用找到的是对象的实际类型Dog ,进行使
用,这个时候就有seeDoor方法。
// 如果一定要调用seeDoor() , 这里只能修改dog的引用类型为Dog. ,即: Dog dog
= new Dog();

即子类赋值给父类

###向下造型:父类引用的对象转换为子类类型。但是对于父类的引用对象一定要是由子类实例化的,也就是说向下造型的出现一般的情况都是和向上造型一起出现的。

// 4. 创建Animal : 动物是动物 , 狗是动物 , 鸡是动物。
Animal a1 = new Animal() ;
Animal a2 = new Dog(); // Dog 和Chicken都是Animal的子类。
Animal a3 = new Chicken() ;
// instanceof : 用于判断 引用 对应的对象是否为某种类型 , 是结果为true ,否
则结果为false.
// a2是动物 , 但是a2本质是狗。 a2不能转换为鸡这个类型。
if(a2 instanceof Dog){ // instanceof的运算结果是true或者false.
// a2 是 Dog , 那么就可以把a2转换为Dog ,然后赋值给Dog类型的引用.
Dog dog1 = (Dog) a2;
dog1.seeDoor(); // 类型转换之后,就可以调用到子类Dog的所有方法。
}
if(a3 instanceof Chicken){
Chicken chicken = (Chicken) a3;
chicken.fly();
}
Chicken chicken = (Chicken) a2; // 没有编译错误。 有运行错误:

###继承中的构造方法
子类的构造方法中必须通过super调用父类的构造方法。因为创建子类之前,必须先创建父类。
子类的构造函数如果没有直接使用super调用父类构造方法,java编译器会自动的加入对父类无参
构造函数的调用(那么要求父类必须有无参构造方法)。

import javafx.beans.binding.DoubleExpression;
// 图形
public class Shape {
int x ;
int y ;
public Shape(){ // 无参构造器函数
System.out.println("Shape的无参构造函数被调用");
}
public Shape(int x , int y){
this.x = x ;
this.y = y ;
System.out.println("Shape的有参构造函数被调用");
}
public double area(){ // 成员函数
System.out.println("Shape的area函数被调用");
return 0 ;
}
}
class Rect extends Shape{
double w ;
double h ;
public Rect(){
5.方法重写(overwrite)
子类从父类继承的方法,如果不能满足子类的需要,可以重写父类的方法。即方法名和参数列表和
父类保持完全一致,方法的实现不同。
子类重写父类的方法之后,子类对象优先调用自己的方法。
子类重写父类的方法的时候,可以在重写的方法中,使用super关键字调用到父类的方法。
super(); // 调用父类的无参构造函数 , 如果要写只能写在构造器函数内部的第一行。
//super(); -- 构造器函数内部,会调用父类型的构造器函数。 如果没有写super() ;
那么编译器会主动添加super().
System.out.println("Rect的无参构造函数被调用");
}
public Rect(int x , int y ){
super(x , y); // 这里就表示调用父类型的有两个参数的构造器函数。
System.out.println("Rect的有两个参构造函数被调用");
}
public Rect(int x , int y , double w , double h){
// 第一行这里隐藏了super() .
this.x = x;
this.y = y ; // this.x = x ; this.y = y 这里两句可以简化为super(x, y)
this.w = w ;
this.h = h ;
System.out.println("Rect的有四个参构造函数被调用");
}
public Rect(double w , double h){
//super(w,h); // 编译错误: super调用父类的构造器,必须是一个父类存在的。
}
// 重写:方法签名(方法的修饰符 , 返回值类型, 方法名,参数等)和父类的方法完全一致。
public double area(){
System.out.println("Rect中的area函数被调用。");
return w * h ;
}
public double area(double w , double h ){
return w * h ;
}
}

###方法重写(overwrite)
子类从父类继承的方法,如果不能满足子类的需要,可以重写父类的方法。即方法名和参数列表和
父类保持完全一致,方法的实现不同。
子类重写父类的方法之后,子类对象优先调用自己的方法。
子类重写父类的方法的时候,可以在重写的方法中,使用super关键字调用到父类的方法。

// 图形
public class Shape {
int x ;
int y ;
public double area(){ // 成员函数
System.out.println("Shape的area函数被调用");
return 0 ;
}
}
class Rect extends Shape{
double w ;
double h ;
// 重写:方法签名(方法的修饰符 , 返回值类型, 方法名,参数等)和父类的方法完全一致。
public double area(){
System.out.println("Rect中的area函数被调用。");
return w * h ;
}
public double area(double w , double h ){
return w * h ;
}

package 关键字

定义类的时候需要指定类的名称。但是如果仅仅将类名作为类的唯一标志,则会出现命名冲突的问
题。
在java中,是用package 来解决命名冲突的问题。因此定义类的时候,一般需要先给类指定一个包
名。
类的真实名字是: 包名 + 类名
包名可以有层次结构,一个类可以有多层包名。
公司域名反写 + 项目名 + 项目模块名 + mvc模式分层

import 关键字

如果要在程序中,使用某个类,可以用该类的全名,这样比较复制。
java.util.Date date = new java.util.Date();
一般使用import 语句导入这个类,然后使用该类

访问控制符

private修饰的成员变量和方法仅仅只能在本类中调用,因此private修饰的内容是对内实现数据的
封装,如果“公开”会增加维护的成本。
public修饰的成员变量和方法可以在任何地方调用,因此public修饰的内容是对外可以被调用的功
能。
在定义类的时候,一般采用成员变量私有化,方法公开的原则。
用protected修饰的成员变量和方法可以被子类及同一个包中的类使用。
默认访问控制即不书写任何访问控制符,默认访问控制的成员变量和方法可以被同一个包中的类调
用。
在这里插入图片描述

return关键字 :

java中方法的定义

java中规定方法必须要指定返回值类型,如果没有返回值类型,可以使用void关键字。
java中使用return关键字,在方法的内部返回数据。
定义方法的语法规则
方法的修饰符 方法的返回值 方法的名字(方法的参数){
方法体
}

package oopday3;
// 方法的定义
// *** ① 方法的参数有哪些,什么类型的 ② 方法是否有返回值,如果有是什么类型的
// ③ 方法取一个什么名字(见名知意) ④ 方法的修饰符
// *** return 用于方法中返回一个数据。 return之后的代码都不能被执行。
// 有时候用return 结束方法的运行。
public class MethodDemo {
// 1. 计算矩形的周长,并返回这个数据。 【方法的参数两个,double , 方法有返回值,
doublepublic double girth(double w , double h){
return 2 * ( w + h) ;//
}
// 2. 输出矩形的周长。 【方法有两个参数 ,double, 无返回值】
public void girth1(double w , double h){
System.out.println("周长:" + 2*(w+h));
}
// static : 静态的
public static void main(String[] args) {
// 0. 创建对象
MethodDemo demo = new MethodDemo();
// 1. 调用girth
demo.girth(10,10); // 静态方法内, 通过对象调用对象非静态方法。
// 2. 调用girth1.
demo.girth1(10,1);
}
}

static关键字

修饰成员变量

用static修饰的成员变量不属于对象的数据结构
static修饰的变量属于类的变量,通常可以通过类名来引用static成员
static成员变量和类的信息一起存储在方法区,而不是在堆内存中
一个类的静态成员变量只有一份,而非静态成员对象有多份,即每个对象都有自己的非静态成员变
量。

修饰成员方法

类中的方法,通常都会涉及到堆具体对象的操作,这些方法在调用时,需要隐式的传递对象的引
用。
void print(){
System.out.println(this.x + “,” + this.y);
}
static修饰的方法则不需要针对对象进行操作,其运行结构仅仅与输入的参数有关系。调用时候直
接通过类名引用。
Math.sqrt(100)
static修饰的方法是属于类的方法,通常用于提供工厂方法,或者工具方法。
static修饰的方法,调用的时候没有具体的对象,因此static修饰的方法不能调用非静态成员变量和
成员方法。

final关键字

修饰类

final关键字修饰的类不可以被继承
对于一些类,设置了final修饰,可以避免滥用继承造成的危害

修饰方法

关键字修饰的方法可以不被重写
防止子类在定义自己的方法的时候,不经意被重写。
修饰成员变量
final修饰成员变量,意为不可以改变。
该成员变量需要在初始化的时候赋值,对象一旦创建,即该值不可以改变。

// 测试java中的关键字final : final - 最终 ,修饰类不能被继承,修饰方法不能被重写,修饰成员
变量,赋值之后,值不可变。
public class FinalDemo {
public static void main(String[] args) {
Coo coo = new Coo() ;//
coo.print(); // 调用的是父类中的print方法。
int age = 18 ;
// age是否为一个合法的年龄数据
if(age >= Coo.MIN_AGE && age <= Coo.MAX_AGE){
System.out.println("年龄正确");
}else{
System.out.println("年龄有误");
}
System.out.println(Math.PI); // java中的Math类型定义的常量PI.
}
}
final class Aoo{ // final修饰的类不能被继承。
}
/*
class Boo extends Aoo{ // 编译错误: Aoo是final修饰的类,不能出现子类。
4. 对象数组
所谓对象数组,对象数组的元素不是基本类型,而是引用类型
对象数组的初始化和基本类型数组的初始化方式一样,只不过元素是对象引用而已。
对象数组创建之后,元素的默认值是null.
}
*/
class Boo{
public final void print(){ // final修饰的方法,不能被重写。
System.out.println("我是Boo中的print方法。");
}
}
class Coo extends Boo{
int count ;
final int size = 100; // final修饰的变量,定义的时候就赋值,赋值之后,值不可以变。
//size = 120 ;// 编译错误: final修饰的成员变量的值不可以修改了。
// 定义常量: ① 用static和final 一起修饰 [static让这个常量可以通过类名调用。 final让这
个变量的值不变,那就是常量了。]
// ② 建议常量的名字全大写。
static final double PI = 3.14;
// 练习: 最大年龄120 。 最小年龄0.
static final int MAX_AGE = 120 ;
static final int MIN_AGE = 0;
/*
public void print(){ // 编译错误: 父类中的print方法,是final修饰的,不能被重写。
}
*/
}

对象数组

所谓对象数组,对象数组的元素不是基本类型,而是引用类型
对象数组的初始化和基本类型数组的初始化方式一样,只不过元素是对象引用而已。
对象数组创建之后,元素的默认值是null.

public class TestPoint {
public static void main(String[] args) {
// 1. 创建5个Point对象,保存在一个变量中。 -- 5个数据,要存在一个变量中, 只有数组
结构符号这个要求。
Point[] ps = new Point[5]; // 创建的数组对象
for(int i = 1; i < 6; i ++){
Point p = new Point(); // 创建对象
p.x = i ;
p.y = i ;
ps[i-1] = p ; // 给数组元素赋值。
}
// 2.修改 ps中的元素的x,y
System.out.println(ps[1].x + ":" + ps[1].y);
ps[1].x = 10 ;
ps[1].y = 10 ;
System.out.println("修改之后:");
System.out.println(ps[1].x + ":" + ps[1].y);
// 3. 输出所有的点的数据
for(int i = 0 ; i < ps.length ; i++){
// System.out.println(ps[i]); // ps[i]输出的是Point的"包名.类名@16进制的整
数"
System.out.println(ps[i].x +"," + ps[i].y);
}
}
}
class Point {
int x ;
int y ;
public Point(){
}
public Point(int x , int y){
this.x = x ;
this.y = y ;
}
}

二维数组

数组的元素可以为任何类型,也包括数组类型。
二维数组: 数组的元素如果是一个数组,那么这个数组就被称为二维数组

import java.util.Arrays;
// 二维数组: 数组中的元素依然是一个数组,就被称为二维数组。
public class Array2Demo {
public static void main(String[] args) {
// 基本数据类型的2维数组 :
int[][] arr = new int[5][];// 定义二维数组的时候,需要设置第一维长度。
arr[0] = new int[5]; // 数组的第一个元素,是一个长度为5的整形数组。
arr[1] = new int[5];
arr[2] = new int[4];
arr[3] = new int[4];
arr[4] = new int[4];// 由于数组中的元素的长度不一致,所以呢,定义这个二维数组
的时候,只能确定第一维的长度,第二维的长度由每个元素决定。
// 遍历二维数组: 循环的嵌套
// 把数组的每个元素输出在一行显示
for(int i = 0 ; i < arr.length ;i ++){
// arr[i] 就是数组中的每个元素(这个元素还是数组,素以呢就继续使用for循环,遍
历这个元素)
for(int j = 0 ; j < arr[i].length ; j ++){
System.out.print(arr[i][j] + "\t");
}
System.out.println();
}
System.out.println("_________________________________");
// 定义一个长度是5的数组,数组的元素还是一个长度为5的数组。
int[][] arr1 = new int[5][5];
// 遍历数组
for(int i=0 ; i < arr1.length ; i++){
System.out.println(Arrays.toString(arr1[i]));
}
// 二维数组初始化
System.out.println("_________________________________");
String[][] strs = {{"A","A","A","A"},{"B","B","B","B"},
{"C","C","C","C"}};
for(int i=0 ; i < strs.length ; i++){
System.out.println(Arrays.toString(strs[i]));
}
// 二维数组定义
Point[][] ps = {{new Point(1,2) , new Point(1,2)} ,
{new Point(1,2) , new Point(1,2)},
{new Point(1,2) , new Point(1,2)},
{new Point(1,2) , new Point(1,2)}};
System.out.println("------------------------");
for(int i=0 ; i < ps.length; i ++){
6. 抽象类
用abstract关键字修饰的类称之为抽象类。
抽象类不能实例化,抽象类的意义在于“被继承”。
抽象类为子类“抽象”出公共部分,通常也定义了子类所必须实现的抽象方法。
一个抽象类可以有抽象方法,也可以有非抽象方法
一个类继承了抽象类,那么必须实现父类的抽象方法,除非该类依然定义为抽象类。
抽象类的使用
System.out.println(ps[i][0].x +"," +ps[i][0].y +"\t" + ps[i]
[1].x + ","+ ps[i][1].y );
}
}
}

抽象类

用abstract关键字修饰的类称之为抽象类。
抽象类不能实例化,抽象类的意义在于“被继承”。
抽象类为子类“抽象”出公共部分,通常也定义了子类所必须实现的抽象方法。
一个抽象类可以有抽象方法,也可以有非抽象方法
一个类继承了抽象类,那么必须实现父类的抽象方法,除非该类依然定义为抽象类。
抽象类的使用

import java.security.AlgorithmConstraints;
// abstract : 抽象, java关键字abstract ,用于修饰类,表示这个类是一个抽象类。
// *** 抽象类中,可以定义抽象方法。
public abstract class Shape {
int x ;
int y ;
/*
public double area(){ // 实现了的方法。 这里并不能体现出面积的计算公式 ,因为当前
这个类型不太方便计算面积。
return 0;
}
*/
public abstract double area();// 这个是一个抽象方法, 只是定义了方法,并没有实
现方法。
// 定义了一个规范,那就是所有Shape类型的子类,都
必须实现area方法。
}
class Circle extends Shape{ // 继承了抽象类之后, 必须要重写父类的抽象方法。
int r ; // 半径
public double area(){ // 方法的实现 。
return Math.PI * r * r ; // 计算面积的公式。
}
}
class Rect extends Shape{
double w;
double h;
public double area(){// 继承了抽象类之后, 必须要重写父类的抽象方法。
return w * h;
}
}
/* 编译错误: 非抽象类中,不能出现抽象方法。
class Other{
public abstract double area();
}
*/
/* 抽象类中,可以有抽象方法,也可以没有抽象方法。
abstract class Other{
public double area(){
return 10 ;
}
}
*/
// 如果父类有抽象方法,子类要么实现这些抽象方法,要么自己依然定义为抽象类。
abstract class SanJiao extends Shape{
}

接口的使用

接口可以看成是特殊的抽象类。
接口中只能定义常量和抽象方法。
一个类可以实现多个接口,多个接口之间用逗号分隔。这个类需要实现所有接口的抽象方法。
接口可以作为一种类型声明变量,一个接口类的变量可以引用实现了该类的对象。通过该引用,调
用接口中的方法(实现类中提供了接口方法的实现)
接口间可以存在继承关系,一个接口可以通过extends关键字继承另外一个接口。
子接口继承了父接口中定义的所有方法。

// interface - 接口: 接口用于制定规范,java中的接口类型中,只能写常量的定义, 抽象方
法的定义。
// 定义好接口之后, 可以通过类实现接口 ,然后类中重写这些接口中定义的方法。
// 接口是抽象的,不能创建对象。
public interface Animal {
// 定义常量
static final String OLDER = "女娲";
// 定义抽象方法。
void eat(); // 接口中的方法默认是public abstract . 所以可以省略这两个关键字。
public abstract void sleep();
public abstract void sing();
}
// Cat实现了Animal接口, 所以Cat是Animal.
class Cat implements Animal{// 类需要实现接口中的所有抽象方法, 否则把类设置为
abstract类。
String pinZhong;
String name;
@Override
public void eat() {
System.out.println("吃东西");
}
@Override
public void sleep() {
System.out.println("睡觉");
}
@Override
public void sing() {
System.out.println("喵喵叫....");
}
public void catchMouse(){
System.out.println("抓老鼠");
}
}

子接口继承父接口

// ** java中规定extends 是单继承(一个类只能extends一个父类)。
// java中可以一个类同时实现多个接口。 (一个类能够 implements 多个接口。)
// java中的类可以继承父类,同时实现某些接口。
//Tiger 继承了Animal中的eat , sleep , sing等方法。
// ** 因为Tiger 依然是一个interface类型, 所以这里不重写父接口中的方法。
public interface Tiger extends Animal {
public abstract void milk(); // Tiger具有的方法
}
class HuaNan implements Tiger{
@Override
public void eat() {
}
@Override
public void sleep() {
2.内部类
}
@Override
public void sing() {
}
@Override
public void milk() {
}
}
class DongBeiTiger implements Tiger{
@Override
public void eat() {
}
@Override
public void sleep() {
}
@Override
public void sing() {
}
@Override
public void milk() {
}
}
// HeiLoingJiangTiger :可以是 DongBeiTiger , Tiger , Animal , Intro.
class HeiLoingJiangTiger extends DongBeiTiger implements Intro{
@Override
public void print() {
}
}

一个类实现多个接口

// Intro ,定义一个打印成员变量的方法。
// Intro制定了一个规范, 实现Intro接口的类,必须提供一个print方法。
public interface Intro {
void print();
}
// 一个类可以实现多个接口。那么这个类需要实现每个接口中定义的方法
class Mouse implements Animal , Intro {
String name;
String color;
@Override
public void eat() {
System.out.println("老鼠在偷吃东西。");
}
@Override // 空实现: 语法规则是有{}的 , 但是{}内部没有代码。
public void sleep() {
}
@Override
public void sing() {
}
@Override
public void print() {
System.out.println(this.name + "是" + this.color);
}
}

内部类

一个类可以定义在另外一个类的内部,定义在内部的类称为内部类,其所在的类称之为外部类。
定义在内部的类,一般只服务于其外部类,堆外部类具备可见性,内部类可以直接使用外部类的成
员及方法。
通常内部类不能独立于外部类存在,一般设置内部类为private。在外部类之前创建内部类对象,
当一个类存在的价值仅仅为某一个类服务时,应使其成为那个类的内部类。
内部类一般情况下堆外不可见,除了包含它的外部类外,其他类无法访问到它。
内部类可以很方便的访问其外部类的私有属性

// 内部类:类的内部包含一个其它类,这个被包含的类,就被称为内部类。
// *** 内部类对象的创建,需要依赖于外部类对象。 因此先创建外部类对象,然后借助于外部
类对象,创建内部类。
// 语法规则:外部类的对象.new 内部类();
public class Outer {
private String name ;
private int x ;
private int y ;
public void out(){
System.out.println("我是外部类的out方法。");
}
// 内部类
class Inner{
String name ; // 内部类的成员变量。
String hobby; // 内部类的成员变量。
// 定义一个方法, 用于输出外部类的成员变量的值。
public void print(){
// 访问外部类的成员变量。
// 内部类的成员变量name , 和外部类的成员变量name重名。 优先使用内部类
的成员变量。
// Outer.this.name : 通过外部类的类名.this来访问外部类的成员变
量。
System.out.println(Outer.this.name + ":" + x +":" + y);
System.out.println("内部类的成员变量:" + name + hobby);
// 调用外部类的成员方法。
out();
}
}
public static void main(String[] args) {
2.2静态内部类
使用static修饰的成员内部类称为静态内部类,在外部类加载时存在
2.3匿名内部类
如果在一段程序中需要创建一个类的对象(通常这个类需要实现某个接口或者继承某个类),而且
对象创建后,这个类的价值也就不存在了,这个类可以不必命名,称之为匿名内部类。
Outer outer = new Outer();
outer.out();// 调用自己类中定义的方法。
outer.x = 10;
outer.y = 20 ;
outer.name = "xxxx";
//Inner in = new Inner(); // 编译错误:Inner是Outer中定义的内部类, 语法
规定需要"外部类的对象.new 内部类()"创建对象。
Inner in = outer.new Inner();
in.name="小红";
in.hobby="喝奶茶";
// 调用内部类的方法。
in.print();
// 链式操作
System.out.println("____________________________");
Inner in1 = new Outer().new Inner();//
in1.print();
}
}

匿名内部类

如果在一段程序中需要创建一个类的对象(通常这个类需要实现某个接口或者继承某个类),而且
对象创建后,这个类的价值也就不存在了,这个类可以不必命名,称之为匿名内部类。

在这里插入图片描述

值传递&引用传递

如果一个方法的参数为引用类型,直接修改该参数会对其造成影响。
如果一个方法的参数为引用类型,该方法中又创建了新对象,不会对实际参数造成影响。
如果一个方法的参数为字符串,该方法中赋值了一个新字符串,不会对实际参数造成影响
如果一个方法的参数为原始类型,该方法不会对实际参数造成影响。

// ** arguments : 参数
public class ArgumentsDemo {
public static void main(String[] args) {
Point point = new Point();
point.x = 10 ;
point.y = 10 ;
point.print(); // 输出点 (10,10)
// testPoint(point); // 实际参数, 是引用类型。
// point.print(); // 输出点(11 ,10)
testPoint1(point); // 实际参数,是引用类型。
point.print(); // 输出点(10,10)
System.out.println("---------------特殊的字符串引用类型-----------------
-");
String str = "你好世界"; // 创建对象, 赋值给引用。
testStr(str);
System.out.println("最后的str:" + str); //
System.out.println("----------值传递----------");
int i = 3;
int k = 5;
testInt(i,k);
System.out.println("最后的i,k:" + i +"," +k);
}
public static void testPoint(Point p){ // 参数是引用类型
p.right(); // 右边移动一个位置。
}
public static void testPoint1(Point p){
p = new Point(); // 给引用赋值了一个新对象。 实际参数传入的引用对应的对象不会
被修改。
p.right();
}
public static void testStr(String str){
System.out.println("str:" + str); // 使用。
// 每个字符串都是一个新对象。
str = "中国"; // 把字符串对象"中国"的引用地址 ,赋值给str这个应用了。
System.out.println("str:" + str);
}
public static void testInt(int i , int k){ // 基本数据类型, 值传递, 把
i,k的值取出来传入这个方法中使用。
i = 10*i;
k = 10*k;
System.out.println("i=" +i +"," + "k=" +k);
}
}

== 和equals的区别

==基本数据类型判断数据是否相等
==引用类型,判断引用类指向的地址是否相等,即是否为同一个对象。
equals是父类Object中提供的的一个equals方法,用于制定两个对象是否相等的比较规则。
Object中的equals默认是比较两个对象的地址是否相同。
子类重写父类的equals方法,自定义比较规则:
比如: 判断两个点是否相同,可以判断两个点的x位置和y位置同时相等,则两个点相同。
如果两个对象比较equals为true ,那么这依然不能说明是否为同一个对象。
重写类的equals方法: 使用idea的自动生成

// 定义类型: 成员变量,成员方法。
// *** java中的所有类都有父类。 如果你定义的类型没有写extends那个父类,那么这个类的父类
就是Object 。 一般省略extends Object.
// 继承父类的属性 和 方法 ,如果父类的方法不满足子类的需求, 就重写父类的方法。
public class Point extends Object {
int x;
int y;
public void up(){
this.y ++ ;
}
public void down(){
this.y --;
}
public void left(){
this.x --;
}
public void right(){
this.x ++;
}
public void print(){
System.out.println("(" + this.x + "," + this.y + ")");
}
@Override
public boolean equals(Object o) {
// 判断是否为自己
if (this == o)
return true;
// 和空比较,直接就是false.
// getClass() != o.getClass() .如果是不同的类型进行比较,直接就是false.
// ** getClass() ,获取到的是对象的类型。
if (o == null || this.getClass() != o.getClass())
return false;
// 因为o不是null, 又是同种类型,所以就强制数据类型。
Point point = (Point) o;
// x ,y 同时相等,返回true, 否则返回false.
return x == point.x && y == point.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
// == : 用于判断基本数据类型的数据值是否相等 , 用于判断引用类型的地址是否相等。
// ** 如果引用地址相等,说明一定是指向的同一个对象,否则,说明是指向不
同的对象。
// equals: 类中的方法 , 用于判断对象的内容是否相等。
public class EqualsDemo {
public static void main(String[] args) {
int a = 10 ;
int b = 10 ;
System.out.println(a == b); // true.
Point p1 = new Point();
p1.x = 10 ;
p1.y = 10 ;
Point p2 = new Point();
p2.x = 10 ;
p2.y = 10 ;
System.out.println("p1:" + p1);
System.out.println("p2:" + p2);
System.out.println(p1 == p2); // 用于==判断引用类型地址是否相等。 false
Student stu1 = new Student("1001" , "小红" ,"java2202");
Student stu2 = new Student("1001" , "小红" ,"java2202");
System.out.println("stu1:" + stu1);
System.out.println("sut2:" +stu2);
System.out.println(stu1 == stu2);
Student stu3 = stu1;
System.out.println(stu3 == stu1); // true. 如果两个引用使用==判断,结果true,说明这是引用的同一个对象。
// *** 如果规定 Point类型,如果x ,y 和另一个对象的x,y相等,我们就认为这两个
点是同一个点。
// 如果规定Student类型,code, name, className各自相等,就认为是同一个
学生。
// ** 如果没有重写equals方法
// System.out.println(p1.equals(p2)); // false . ** Object中定义的
equals方法,就是用==判断两个对象的地址是否相等。
// ** 如果重写了equals方法
System.out.println(p1.equals(p2)); // true , 重写了equals方法,制定了比
较规则: x ,y同时相等,则两个点相等。
Point p3 = new Point();
p3.x = 10 ; p3.y = 5;
System.out.println(p1.equals(p3)); // false 。 因为x和y没有同时相等。所以
equals方法,返回false.
System.out.println(p1.equals(null)); // false. 空不能和任何对象相等。
System.out.println(p1.equals(stu3)); // false. 不同类型,不能比。
System.out.println(p1.equals(p1)); // true , 自己和自己相等。
}
}
import java.util.Objects;
public class EqualsDemo1 {
public static void main(String[] args) {
String str = "abc"; // 创建了字符串对象,赋值给str
String str1 = new String("abc"); // 创建了字符串对象,赋值给str1.
System.out.println(str == str1); // false , 引用类型,== 判断对象的地址
是否相等。
System.out.println(str.equals(str1)); // true , equals方法,用于判断对
象的内容是否相等。
// 1. 创建学生对象
Student stu1 = new Student("1001" , "小红" ,"java2202");
Student stu2 = new Student("1001" , "小红" ,"java2202");
Student stu3 = stu1;
Student stu4= new Student("1002" , "小红" ,"java2202");
// 2. 判断对象是否相等
System.out.println(stu1.equals(stu3)); // true
System.out.println(stu1.equals(stu2)); // true
System.out.println(stu1.equals(null)); // false
System.out.println(stu1.equals(stu4)); // false
// 3. 使用Objects.equals(obj ,obj); 判断对象是否相等。
System.out.println(Objects.equals(stu1, stu4)); // false
Car c = new Car();
c.pinPai = "宝马";
Car c1 = new Car();
c1.pinPai ="宝马";
System.out.println("====================================");
System.out.println(Objects.equals(c ,c1)); // false . Objects.equals
进行c,c1的比较的时候,调用c,c1的类型Car中的equals方法。
// Car中的equals方法,是继承Object中的,比较的是两个对象的地址是否相等。
ChangAnCar ca = new ChangAnCar();
ca.pinPai = "xx";
ca.name ="zzz";
ChangAnCar ca1 = new ChangAnCar();
ca1.pinPai = "xx";
ca1.name ="zzz";
System.out.println(ca.equals(ca1)); // true
System.out.println(Objects.equals(ca,ca1)); //Objects.equals(ca,ca1)
,本质就是调用ca.equals(ca1)
System.out.println(ca.equals(c)); // c instanceof ChangAnCar 是
false.
System.out.println("c instanceof ChangAnCar :" + (c instanceof
ChangAnCar ));
}

面向对象三大特性:

封装

通过private关键字对成员变量进行修饰,提供公开的getter和setter方法用于简单地对成员变量进
行取值和赋值。
可以隐藏具体的细节,实现代码安全
在Idea中,自动生成getter/setter的快捷键为:
右键–generate或alt+insert -->getter and setter
选择要生成的成员变量

继承

A类通过extends关键字,继承B类,Java是中是单继承,一个子类只能有一个父类,一个父类可以
有多个子类
继承能够提高代码的重用性
Java是中是单继承,一个子类只能有一个父类,一个父类可以有多个子类

多态

对象是多种状态的。
父类的引用指向子类的对象
Father s=new Son();

代码块

static{
静态代码块
}{
非静态代码块
}

// 静态代码块
// 非静态代码块
public class CodeBlockDemo {
private int x ;
static double pi;
static { //静态代码块, 类加载完成的时候,执行静态代码块。
System.out.println("这个是静态代码块");
pi = 3.14;
}
{ // 非静态代码块 , 创建对象的时候,执行非静态代码块。
System.out.println("非静态的代码块");
this.x = 10 ;
}
public CodeBlockDemo(){
System.out.println("对象创建成功了。");
}
// 要求: 类加载的时候,给变量pi初始化为3.14 . 对象创建的时候,给变量x ,初始化为10.
public static void main(String[] args) {
CodeBlockDemo cbd = new CodeBlockDemo();
System.out.println(CodeBlockDemo.pi);
System.out.println(cbd.getX());
CodeBlockDemo cbd1 = new CodeBlockDemo();
System.out.println(cbd1.getX());
}
// 成员方法
public void add(){
x++;
}
public void add(int k){
this.x = x*k;
}
// get & set
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
// equals & hashCode
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof CodeBlockDemo)) return false;
CodeBlockDemo that = (CodeBlockDemo) o;
return getX() == that.getX();
}
@Override
public int hashCode() {
return Objects.hash(getX());
}
}

在学习面向对象中,有许多概念的东西需要弄清楚,什么这个继承这个那个有实现了那个接口,很容易忘记。然后就不知道据他要干什么了,总之就是得慢慢理清思路,多做几道题。多去理理那个父亲有多少儿子,那个儿子有继承父亲的那些内容,重写了嘛等等等等。有许多东西刚开始学可能会搞不懂概念。
多看每天学的内容,重要的是把内容贯通起来在一些题目中就慢慢熟练些了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值