类与对象

类和对象的区别和分割

  1. 类是形象的,概念的,代表一类事物,比方人类,猫类.., 即它是数据类型.
  2. 对象是具体的,理论的,代表一个具体事物, 即是实例.
  3. 类是对象的模板,对象是类的一个个体,对应一个实例

对象在内存中存在模式!

字符串实质上是一个援用类型,依照jvm的规定会把字符串放在办法区的常量池两头。

栈中的是对象援用(对象名),实际上的对象在堆中。

// 创立Person 对象// p1 是对象名(对象援用)// new Person() 创立的对象空间(数据) 才是真正的对象Person p1 = new Person();// 对象的属性默认值,恪守数组规定:

属性/成员变量/字段

从概念或叫法上看: 成员变量 = 属性 = field(字段) (即成员变量是用来示意属性的,对立叫属性)

class Car {    String name;//属性, 成员变量, 字段field    double price;    String color;    String[] master;//属性能够是根本数据类型,也能够是援用类型(对象,数组)}

属性是类的一个组成部分,个别是根本数据类型, 也可是援用类型(对象,数组)。比方后面定义猫类的 int age 就是属性

注意事项和细节阐明

  1. 属性的定义语法同变量,示例:拜访修饰符属性类型属性名;
    拜访修饰符: 管制属性的拜访范畴
    有四种拜访修饰符public, proctected, 默认, private ,前面我会具体介绍
  2. 属性如果不赋值,有默认值,规定和数组统一。

如何创建对象

  1. 先申明再创立
    Cat cat ; //申明对象cat
    cat = new Cat(); //创立
  2. 间接创立
    Cat cat = new Cat();

如何拜访属性

根本语法

对象名.属性名;

cat.name ;
cat.age;
cat.color;

Person p1=new Person0;p1.age=10;p1.name="小明";Person p2=p1;//把p1赋给了p2,让p2指向p1System.out.println(p2.age);

请问:p2.age到底是多少? 10 并画出内存图:

外围:援用传递传递的是地址。

成员办法

在某些状况下,咱们要须要定义成员办法(简称办法)。

办法的调用机制原理!

成员办法的益处

  1. 进步代码的复用性
  2. 能够将实现的细节封装起来,而后供其余用户来调用即可

成员办法的定义

拜访修饰符 返回数据类型 办法名(形参列表..){//办法体    语句;    return 返回值;}// 如果办法是void,则办法体中能够没有return 语句,或者只写return;

拜访修饰符(作用是管制办法应用的范畴)
如果不写默认拜访,[有四种: public, protected, 默认, private]

办法不能嵌套定义!

成员办法传参机制

根本数据类型,传递的是值(值拷贝),形参的任何扭转不影响实参!

援用数据类型的传参机制

援用类型传递的是地址(传递也是值,然而值是地址),能够通过形参影响实参!

栈的值是地址,改的时候批改的是对应堆中的值。

例子:

public class MethodParameter02 {     //编写一个main办法    public static void main(String[] args) {        //测试        B b = new B();        // int[] arr = {1, 2, 3};        // b.test100(arr);//调用办法        // System.out.println(" main的 arr数组 ");        // //遍历数组        // for(int i = 0; i < arr.length; i++) {        //     System.out.print(arr[i] + "\t");        // }        // System.out.println();        //测试        Person p = new Person();        p.name = "jack";        p.age = 10;        b.test200(p);        //测试题, 如果 test200 执行的是 p = null ,上面的后果是 10        //测试题, 如果 test200 执行的是 p = new Person();..., 上面输入的是10        System.out.println("main 的p.age=" + p.age);//10000     }}class Person {    String name;    int age; }class B {    public void test200(Person p) {        //p.age = 10000; //批改对象属性        //思考        p = new Person();        p.name = "tom";        p.age = 99;        //思考        //p = null;     }    //B类中编写一个办法test100,    //能够接管一个数组,在办法中批改该数组,看看原来的数组是否变动    public void test100(int[] arr) {        arr[0] = 200;//批改元素        //遍历数组        System.out.println(" test100的 arr数组 ");        for(int i = 0; i < arr.length; i++) {            System.out.print(arr[i] + "\t");        }        System.out.println();    }}

B 类中编写一个办法test100,能够接管一个数组,在办法中批改该数组,看看原来的数组是否变动?会变动

B 类中编写一个办法test200,能够接管一个Person(age,sal)对象,在办法中批改该对象属性,看看原来的对象是否变动?会变动.

p=null 和p = new Person(); 对应示意图

这里再对class B中的p进行批改,因为在Class B中从新new 了一个p,因而p的指针产生了扭转,指向堆中的一个新空间,因而这时批改p的参数,不对main中对象造成影响。

成员办法返回类型是援用类型利用实例

通过这种形式能够编写办法复制对象。

public class MethodExercise02 {     //编写一个main办法    public static void main(String[] args) {        Person p = new Person();        p.name = "milan";        p.age = 100;        //创立tools        MyTools tools = new MyTools();        Person p2 = tools.copyPerson(p);        //到此 p 和 p2是Person对象,然而是两个独立的对象,属性雷同        System.out.println("p的属性 age=" + p.age  + " 名字=" + p.name);        System.out.println("p2的属性 age=" + p2.age  + " 名字=" + p2.name);        //这里老师提醒: 能够同 对象比拟看看是否为同一个对象        System.out.println(p == p2);//false    }}class Person {    String name;    int age;}class MyTools {    //编写一个办法copyPerson,能够复制一个Person对象,返回复制的对象。克隆对象,     //留神要求失去新对象和原来的对象是两个独立的对象,只是他们的属性雷同    //    //编写办法的思路    //1. 办法的返回类型 Person    //2. 办法的名字 copyPerson    //3. 办法的形参 (Person p)    //4. 办法体, 创立一个新对象,并复制属性,返回即可    public Person copyPerson(Person p) {        //创立一个新的对象        Person p2 = new Person();        p2.name = p.name; //把原来对象的名字赋给p2.name        p2.age = p.age; //把原来对象的年龄赋给p2.age        return p2;    }}

办法递归调用

办法递归调用

列举两个小案例,来帮忙大家了解递归调用机制

  1. 打印问题
  2. 阶乘问题
public class Recursion01 {     //编写一个main办法    public static void main(String[] args) {        T t1 = new T();        t1.test(4);//输入什么? n=2 n=3 n=4        int res = t1.factorial(5);         System.out.println("5的阶乘 res =" + res);    }}class T {    //剖析    public void test(int n) {        if (n > 2) {            test(n - 1);        }         System.out.println("n=" + n);    }    //factorial 阶乘    public int factorial(int n) {        if (n == 1) {            return 1;        } else {            return factorial(n - 1) * n;        }    }}

递归重要规定

1.执行一个办法时,就创立一个新的受爱护的独立空间(钱空间)

2.办法的局部变量是独立的,不会相互影响,比方n变量

3.如果办法中应用的是援用类型变量(比方数组,对象),就会共享该引
用类型的数据。
4.递归必须向退出递归的条件迫近,否则就是有限递归,呈现StackOverflowError
5.当一个办法执行结束,或者遇到return,就会返回,恪守谁调用,就
将后果返回给谁,同时当办法执行结束或者返回时,该办法也就执行结束。

递归调用利用实例-汉诺塔

public class HanoiTower {     //编写一个main办法    public static void main(String[] args) {        Tower tower = new Tower();        tower.move(64, 'A', 'B', 'C');    }}class Tower {    //办法    //num 示意要挪动的个数, a, b, c 别离示意A塔,B 塔, C 塔    public void move(int num , char a, char b ,char c) {        //如果只有一个盘 num = 1        if(num == 1) {            System.out.println(a + "->" + c);        } else {            //如果有多个盘,能够看成两个 , 最上面的和下面的所有盘(num-1)            //(1)先挪动下面所有的盘到 b, 借助 c            move(num - 1 , a, c, b);            //(2)把最上面的这个盘,挪动到 c            System.out.println(a + "->" + c);            //(3)再把 b塔的所有盘,挪动到c ,借助a            move(num - 1, b, a, c);        }    }}

递归调用利用实例-八皇后问题

八皇后问题,是一个古老而驰名的问题,是回溯算法的典型案例。该问题是国内西洋棋棋手马克斯·贝瑟尔于1848 年提出:在8×8 格的国际象棋上摆放八个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

  1. 第一个皇后先放第一行第一列
  2. 第二个皇后放在第二行第一列、而后判断是否OK,如果不OK,持续放在第二列、第三列、顺次把所有列都放完,找到一个适合
  3. 持续第三个皇后,还是第一列、第二列...….直到第8个皇后也能放在一个不抵触的地位,算是找到了一个正确解
  4. 当失去一个正确解时,在栈回退到上一个栈时,就会开始回溯,行将第一个皇后,放到第一列的所有正确解,全副失去.
  5. 而后回头持续第一个皇后放第二列,前面持续循环执行1,2,3.4的步骤
  6. 阐明:实践上应该创立一个二维数组来示意棋盘,然而实际上能够通过算法,用一个一维数组即可解决问题. arr[8]={0,4,7,5.2, 6,1.3)//对应arr下标示意第几行,即第几个皇后,arr[i]= val , val示意第i+1个皇后,放在第i+1行的第val+1列

办法重载(OverLoad)

根本介绍

java 中容许同一个类中,多个同名办法的存在,但要求形参列表不统一!

重载的益处

  1. 加重了起名的麻烦
  2. 加重了记名的麻烦

注意事项和应用细节

1)办法名: 必须雷同

2)形参列表: 必须不同(形参类型或个数或程序,至多有一样不同,参数名无要求)

3)返回类型: 无要求

可变参数

基本概念

java 容许将同一个类中多个同名同性能但参数个数不同的办法,封装成一个办法。就能够通过可变参数实现

根本语法

拜访修饰符返回类型办法名(数据类型... 形参名) {}

看一个案例类HspMethod,办法sum。

public class VarParameter01 {     //编写一个main办法    public static void main(String[] args) {        HspMethod m = new HspMethod();        System.out.println(m.sum(1, 5, 100)); //106        System.out.println(m.sum(1,19)); //20    }}class HspMethod {    //能够计算 2个数的和,3个数的和 , 4. 5, 。。    //能够应用办法重载    // public int sum(int n1, int n2) {//2个数的和    //     return n1 + n2;    // }    // public int sum(int n1, int n2, int n3) {//3个数的和    //     return n1 + n2 + n3;    // }    // public int sum(int n1, int n2, int n3, int n4) {//4个数的和    //     return n1 + n2 + n3 + n4;    // }    //.....    //下面的三个办法名称雷同,性能雷同, 参数个数不同-> 应用可变参数优化    //老韩解读    //1. int... 示意承受的是可变参数,类型是int ,即能够接管多个int(0-多)     //2. 应用可变参数时,能够当做数组来应用 即 nums 能够当做数组    //3. 遍历 nums 求和即可    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;    }}

注意事项和应用细节

1)可变参数的实参能够为0个或任意多个。

2)可变参数的实参能够为数组。

3)可变参数的实质就是数组。

4)可变参数能够和一般类型的参数一起放在形参列表,但必须保障可变参数在最初

5)一个形参列表中只能呈现一个可变参数

public void f3(int... nums1, double... nums2) (X谬误)

作用域

根本应用

1.在java编程中,次要的变量就是属性(成员变量)局部变量

2.咱们说的局部变量个别是指在成员办法中定义的变量

3.java中作用域的分类

全局变量:也就是属性,作用域为整个类体 (Cat类:cry eat等办法应用属性)

局部变量:也就是除了属性之外的其余变量,作用域为定义它的代码块中!

4.全局变量(属性)能够不赋值,间接应用,因为有默认值,局部变量必须赋值后,
能力应用,因为没有默认值。

public class VarScope {     //编写一个main办法    public static void main(String[] args) {    }}class Cat {    //全局变量:也就是属性,作用域为整个类体 Cat类:cry eat 等办法应用属性    //属性在定义时,能够间接赋值    int age = 10; //指定的值是 10    //全局变量(属性)能够不赋值,间接应用,因为有默认值,    double weight;  //默认值是0.0    public void hi() {        //局部变量必须赋值后,能力应用,因为没有默认值        int num = 1;        String address = "北京的猫";        System.out.println("num=" + num);        System.out.println("address=" + address);        System.out.println("weight=" + weight);//属性    }    public void cry() {        //1. 局部变量个别是指在成员办法中定义的变量        //2. n 和  name 就是局部变量        //3. n 和 name的作用域在 cry办法中        int n = 10;        String name = "jack";        System.out.println("在cry中应用属性 age=" + age);    }    public void eat() {        System.out.println("在eat中应用属性 age=" + age);        //System.out.println("在eat中应用 cry的变量 name=" + name);//谬误    }}

1.属性和局部变量能够重名,拜访时遵循就近准则。

2.在同一个作用域中,比方在同一个成员办法中,两个局部变量,不能重名。

3.属性生命周期较长,随同着对象的创立而创立,随同着对象的销毁而销毁。部分变
量,生命周期较短,随同着它的代码块的执行而创立,随同着代码块的完结而销毁。

4.作用域范畴不同

全局变量/属性:能够被本类应用,或其余类应用(通过对象调用)

局部变量:只能在本类中对应的办法中应用

5.修饰符不同

全局变量/属性能够加修饰符

局部变量不能够加修饰符

构造方法/结构器

[修饰符] 办法名(形参列表){    办法体;}
  1. 结构器的修饰符能够默认, 也能够是public protected private
  2. 结构器没有返回值
  3. 办法名和类名字必须一样
  4. 参数列表和成员办法一样的规定
  5. 结构器的调用, 由零碎实现

根本介绍

构造方法又叫结构器(constructor),是类的一种非凡的办法,它的次要作用是实现对新对象的初始化。它有几个特点:

  1. 办法名和类名雷同
  2. 没有返回值
  3. 在创建对象时,零碎会主动的调用该类的结构器实现对象的初始化。

注意事项和应用细节

1.一个类能够定义多个不同的结构器,即结构器重载

比方:咱们能够再给Person类定义一个结构器,用来创建对象的时候,只指定人名,不须要指定年龄。

2.结构器名和类名要雷同

3.结构器没有返回值

4.结构器是实现对象的初始化,并不是创建对象

5.在创建对象时,零碎主动的调用该类的构造方法

6.如果程序员没有定义结构器,零碎会主动给类生成一个默认无参结构器(也
叫默认结构器). 比方Dog(){}, 应用javap指令反编译看看

能够应用javap Dog.class 查看

7.一旦定义了本人的结构器,默认的结构器就笼罩了,就不能再应用默认的无
参结构器,除非显式的定义一下,即:Dog(){}

javap的应用

javap是JDK提供的一个命令行工具,javap能对给定的class文件提供的字节代码进行反编译。 通过它,能够对照源代码和字节码,从而理解很多编译器外部的工作。

应用格局

javap <options> <classes>

罕用

javap -c -v 类名
  -help  --help  -?        输入此用法音讯  -version                 版本信息  -v  -verbose             输入附加信息  -l                       输入行号和本地变量表  -public                  仅显示公共类和成员  -protected               显示受爱护的/公共类和成员  -package                 显示程序包/受爱护的/公共类                           和成员 (默认)  -p  -private             显示所有类和成员  -c                       对代码进行反汇编  -s                       输入外部类型签名  -sysinfo                 显示正在解决的类的                           零碎信息 (门路, 大小, 日期, MD5 散列)  -constants               显示最终常量  -classpath <path>        指定查找用户类文件的地位  -cp <path>               指定查找用户类文件的地位  -bootclasspath <path>    笼罩疏导类文件的地位

对象创立的流程剖析

class Person{//类Person    int age=90;    String name;    Person(String n,int a){//结构器    name=n;//给属性赋值    age=a;//..    }}Person p=new Person("TIMERRING",20);

流程剖析!

1.加载Person类信息(Person.class) 到办法区,只会加载一次

2.在堆中调配空间(地址)

3.实现对象初始化[3.1默认初始化 age=0 name=null 3.2显式初始化age=90,name=null,3.3结构器的初始化 age =20, name=TIMERRING]

4.在对象在堆中的地址,返回给p(p是对象名,也能够了解成是对象的援用)

this 关键字

能够失常运行,然而是否能够将构造函数的形参改为属性值呢?能够用this。

public class This01 {     //编写一个main办法    public static void main(String[] args) {        Dog dog1 = new Dog("大壮", 3);        System.out.println("dog1的hashcode=" + dog1.hashCode());        //dog1调用了 info()办法        dog1.info();         System.out.println("============");        Dog dog2 = new Dog("大黄", 2);        System.out.println("dog2的hashcode=" + dog2.hashCode());        dog2.info();    }}class Dog{ //类    String name;    int age;    // public Dog(String dName, int  dAge){//结构器    //     name = dName;    //     age = dAge;    // }    //如果咱们结构器的形参,可能间接写成属性名,就更好了    //然而呈现了一个问题,依据变量的作用域准则    //结构器的 name 是局部变量,而不是属性    //结构器的 age  是局部变量,而不是属性    //==> 引出this关键字来解决    public Dog(String name, int  age){//结构器        //this.name 就是以后对象的属性name        this.name = name;        //this.age 就是以后对象的属性age        this.age = age;        System.out.println("this.hashCode=" + this.hashCode());    }    public void info(){//成员办法,输入属性x信息        System.out.println("this.hashCode=" + this.hashCode());        System.out.println(name + "\t" + age + "\t");    }}

java虚构机会给每个对象调配this, 代表以后对象。

this.name 就是以后对象属性name。

深刻了解this

暗藏的this指向本人的堆地址。

this 的注意事项和应用细节

  1. this 关键字能够用来拜访本类的属性、办法、结构器
  2. this 用于辨别以后类的属性和局部变量
  3. 拜访成员办法的语法:this.办法名(参数列表);
  4. 拜访结构器语法:this(参数列表); 留神只能在结构器中应用(即只能在结构器中拜访另外一个结构器, 必须放在第一条语句)

    public class ThisDetail {  //编写一个main办法 public static void main(String[] args) {     // T t1 = new T();     // t1.f2();     T t2 = new T();     t2.f3(); }}class T { String name = "jack"; int num = 100; /* 细节: 拜访结构器语法:this(参数列表);  留神只能在结构器中应用(即只能在结构器中拜访另外一个结构器) 留神: 拜访结构器语法:this(参数列表); 必须搁置第一条语句!!!  */ public T() {     //这里去拜访 T(String name, int age) 结构器     this("jack", 100);     System.out.println("T() 结构器"); } public T(String name, int age) {     System.out.println("T(String name, int age) 结构器"); } //this关键字能够用来拜访本类的属性 public void f3() {     String name = "smith";     //传统形式(依照就近准则,有局部变量先拜访局部变量)     System.out.println("name=" + name + " num=" + num);//smith  100     //也能够应用this拜访属性(精确地就拜访属性)     System.out.println("name=" + this.name + " num=" + this.num);//jack 100 } //细节: 拜访成员办法的语法:this.办法名(参数列表); public void f1() {     System.out.println("f1() 办法.."); } public void f2() {     System.out.println("f2() 办法..");     //调用本类的 f1     //第一种形式     f1();     //第二种形式     this.f1(); }}
  5. this 不能在类定义的内部应用,只能在类定义的办法中应用

this 的案例

public class TestPerson {     //编写一个main办法    public static void main(String[] args) {        Person p1 = new Person("mary", 20);        Person p2 = new Person("mary", 20);        System.out.println("p1和p2比拟的后果=" + p1.compareTo(p2));    }}/*定义Person类,外面有name、age属性,并提供compareTo比拟办法,用于判断是否和另一个人相等,提供测试类TestPerson用于测试, 名字和年龄齐全一样,就返回true, 否则返回false */class Person {    String name;    int age;    //结构器    public Person(String name, int age) {        this.name = name;        this.age = age;    }    //compareTo比拟办法    public boolean compareTo(Person p) {        return this.name.equals(p.name) && this.age == p.age;    }}

文章和代码曾经归档至【Github仓库:https://github.com/timerring/java-tutorial 】或者公众号【AIShareLab】回复 java 也可获取。