【韩顺平java课笔记1】

发布于:2022-12-30 ⋅ 阅读:(642) ⋅ 点赞:(0)

目录

类与对象

类与对象的区别和联系:

属性/成员变量:

注意事项和细节说明:

创建对象

访问属性

类和对象的内存分配机制

Java内存的结构分析:

java创建对象的流程简单分析:

成员方法

方法调用小结

成员方法的定义

方法注意事项和使用细节1

注意事项和使用细节2

注意事项和使用细节2

小总结

成员方法传参机制

引用数据类型的传参机制

克隆对象

递归

递归(recursion)执行机制

递归重要规则

方法重载(OverLoad)

注意事项和使用细节

可变参数(variable parameters)

注意事项和细节

作用域(scope)

注意事项和细节使用

构造器

注意事项和使用细节

对象创建的流程分析

小总结

this关键字

注意事项和细节


类与对象

类与对象的区别和联系:

1、类是抽象的,概念的,代表一类事物,是数据类型。

2、对象是具体的,实际的,代表一个具体事物,即实例。

3、类是对象的模板,对象是类的一个个体,对应一个实例。

属性/成员变量:

1、成员变量=属性=field(字段),成员变量是用来表示属性的。

2、属性是类的一个组成部分,一般是基本数据类型,也可是引用类型(对象,数组)。

class Car{
    String name;
    String[] master;
}

注意事项和细节说明:

1、属性的定义语法:访问修饰符 属性类型 属性名

有四种访问修饰符:public,proctected,默认,private。

2、属性的定义类型可以为任意类型,包含基本类型或引用类型。

3、属性如果不赋值,有默认值,规则和数组一致:

int 0,shot 0,byte 0,long 0,float 0.0,double 0.0,char \u0000, boolean false,String null.

public static void main(String[] args) {
    //创建Person对象
    //p1 是对象名(对象引用)
    //new Person()创建的对象空间(数据)才是真正的对象
    Person p1= new Person();
}

class Person {
    int age;
}

创建对象

1、先声明再创建

Cat cat;//声明对象cat

cat=new Cat();//创建

2、直接创建

Cat cat =new Cat();

访问属性

对象名.属性名

cat.name;

类和对象的内存分配机制

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

Java内存的结构分析:

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

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

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

java创建对象的流程简单分析:

Person p=new Person();
p.name="jack";
p.age=10;

1、先加载Person类信息(属性和方法信息,只会加载一次)

2、在堆中分配空间,进行默认初始化(看规则)

3、把地址赋给p,p就指向对象

4、进行指定初始化,比如p.name="jack'' p.age=10

Person a=new Person();
a.age=10;
a.name="小明";
Person b;
b=a;
System.out.println(b.name);//小明
b.age=200;
b=null;
System.out.println(a.age);//200
System.out.println(b.age);//异常

成员方法

1、成员方法(简称方法) 比如人类除了一些属性外,还有一些行为,这些行为用成员方法才能完成。

public class Method01 {
    public static void main(String[] args) {
        //方法使用:
        //1、方法写好后,要调用(使用)才能输出
        //2、先创建对象,然后调用方法即可
        Person p1=new Person();
        p1.speak();//调用方法
        p1.cal01();
        p1.cal02(5);
        p1.cal02(10);
        //把方法getSum返回的值,赋给变量returnRes
        int returnRes=p1.getSum(10,20);
        System.out.println("getSum方法返回的值="+returnRes);
    }
}
class Person {
    String name;
    int age;
//方法
//添加speak成员方法
//1、public表示公开
//2、void:表示方法没有返回值
//3、speak():speak是方法名,()为形参列表
//4、{}是方法体,写要执行的代码
//5、System.out.println("我是一个好人");表示我们的方法就是输出一句话

public void speak() {
    System.out.println("我是一个好人");
}

//添加cal01方法,计算从1+..+1000的结果
public void cal01(){
    int res =0;
    for(int i=1;i<=1000;i++){
        res +=i;
}
System.out.println("计算结果="+res);
}

//该方法可以接收一个数n,计算从1+..n的结果
//1、(int n)形参列表,表示当前有一个形参n,可以接收用户输入。
public void cal02(int n){
    int res =0;
    for(int i=1;i<=n;i++){
        res +=i;
}
System.out.println("计算结果="+res);

//可以计算两个数的和
//1、int:表示方法执行后,返回一个int值
//2、形参列表,2个形参
//3、return res;表示把res的值,返回
public int getSum(int num1,int num2){
    int res=num1+num2;
    return res;
}
}

方法调用小结

1、当程序执行到方法时,就会开辟一个独立的空间(栈空间)

2、当方法执行完毕,或执行到return语句时,就会返回

3、返回到调用方法的地方

4、返回后,继续执行方法后面的代码

5、当main方法(栈)执行完毕,整个程序退出

//main方法
int[][]map={{0,0,1},{1,1,1},{1,1,3}};
MyTools tool=new MyTools();
//使用方法
tool.printArr(map);


class MyTools {
//方法,接收一个二维数组
    public void printArr(int[][] map) {
//对传入的map数组进行遍历输出
        for(int i=0;i<map.length;i++) {
            for(int j=0;j<map[i].length;j++){
                    System.out.print(map[i][j]+"");
                    }
}
    }
        }

成员方法的好处:提高代码的复用性;可以将实现的细节封装起来,然后供其他用户来调用即可。

成员方法的定义

访问修饰符 返回数据类型 方法名(形参列表){//方法体

        语句;

        return 返回值;

}

1、形参列表:表示成员方法输入cal(int n)

2、返回数据类型:表示成员方法输出,void表示没有返回值

3、方法主体:表示为了实现某一功能代码块

4、return语句不是必须的(例如 void)

方法注意事项和使用细节1

1、访问修饰符(作用控制方法使用范围)

不写则默认访问,有四种:public,protected,默认,private

2、返回数据类型:

①、一个方法最多有一个返回值,如果返回多个结果,则返回数组。

//main方法
AA a=new AA();
int[] res =a.getSumAndSub(1,4);
System.out.println("和="+res[0]);
System.out.println("差="+res[1]);


class AA{
    public int[] getSumAndSub(int n1,int n2) {
        int[] resArr =new int[2];//创建一个数组
        resArr[0]=n1+n2;
        resArr[1]=n1-n2;
        return resArr;
}
}

②、返回类型可以为任意类型,包含基本类型和引用类型(数组,对象)

③、若方法要求有返回数据类型,则方法体中最后的执行语句必须为return值;而且要求返回值类型必须和return的值类型一致或兼容

public double f1() {
    double d1=1.1*3;
    int n=100;
    return n;//int->double 而double->int(×)
}
public double f2() {
    double d1=1.1*3;
    return 1.1;//int->double
}

④、方法是void,则方法体中可以没有return语句,或者只写return;

public void f2(){
    System.out.println("hello1");
    return;
}

⑤、方法名

遵守驼峰命名法,最好见名知义,表达出该功能的意思。

注意事项和使用细节2

形参列表

①、一个方法可以有0个参数,也可以有多个,用逗号隔开。

②、参数类型可以为任意类型(基本类型/引用类型)。

③、调用带参数的方法时,对应着参数列表传入相同类型或兼容类型的参数。

④、方法定义时的参数称为形式参数,简称形参;方法调用时的参数称为实际参数,简称实参

实参和形参的类型要一致或兼容、个数、顺序必须一致。

方法体:里面写完成功能的具体的语句,可以为输入、输出、变量、运算、分支、循环、方法调用,当里面不能再定义方法。即方法不能嵌套定义

注意事项和使用细节3

方法调用细节

①、同一个类中的方法调用:直接调用即可。

//main方法
A a=new A();
a.sayOk();

class A {
    public void print(int n){
        System.out.println("print()方法被调用 n="+n);
}
    public void sayOk() {//sayOk调用print(直接调用即可)
    print(10);
    System.out.println("继续执行sayOk()");
}
//输出结果为:
//print()方法被调用 n=10
//继续执行sayOk()

②、跨类中的方法A类调用B类方法:需要通过对象名调用。

//main方法
A a=new A();
a.sayOk();

class A {
    public void print(int n){
        System.out.println("print()方法被调用 n="+n);
}
    public void sayOk() {//sayOk调用print(直接调用即可)
    print(10);
    System.out.println("继续执行sayOk()");
}
public void m1(){
    System.out.println("m1()方法被调用");//先输出这句话
    B b=new B();
    b.hi();
    System.out.println("m1()继续执行");//最后输出这句话
    }
}
class B {
    pubic void hi(){
    System.out.println("B类中的hi()被执行");//然后输出这句话
    }
}
        

③、跨类的方法调用和方法的访问修饰符相关。

小总结

类定义的完善:

class 类名{

属性(成员变量);

成员方法;

}

成员方法传参机制

public static void main(String[] args) {
    int a=10;//实参
    int b=20;
    AA obj=new AA();
    obj.swap(a,b);//调用swap
    System.out.println("main 方法a="+a"b="+b);//③10 20 主栈的a和b没发生交换
}
}
class AA{
    public void swap(int a,int b){//swap栈的变化不影响主栈
        System.out.println("\n交换前\na="+a+"\tb="+b);//①10 20
        //完成a和b的交换
        int tmp=a;
        a=b;
        b=tmp;
        System.out.println("\n交换后\na="+a+"\tb="+b);//②20 10
}
}

结论:基本数据类型,传递的是值(值拷贝),形参的任何改变不影响实参。

引用数据类型的传参机制

public class MethodParameter02{
    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");//② 200 2 3
    }
    System.out.println();
    }
}
class B {
    public void test100(int[]arr){
        arr[0]=200;//修改元素
        //遍历数组
        System.out.println("text100的 arr数组");
        for(int i=0;i<arr.length;i++){
            System.out.print(arr[i]+"\t");//① 200 2 3
    }
    System.out.println();

}

结论:引用类型传递的是地址(传递也是值,但是值是地址),可以通过形参影响实参!

//main方法
Person p =new Person();
B b=new B();
p.nae="jack";
p.age=10;

b.text200(p);//p是引用 存的是对象的地址
System.out.println("main 的p.age="+p.age);//10000
    }
}
class Person{
    String name;
    int age;
}
class B{
    public void text200(Person p){
        p.age=10000;
}
Person p=new Person();
B b=new B();
p.age=10;

b.text200(p);
System.out.println("main 的p.age="+p.age);//10
    }
}
class person{
    String name;
    int age;
}
class B{
    public void text200(Person p){
        p=null;//指向空
}
Person p=new Person();
p.age=10;

b.text200(p);
System.out.println("main 的p.age="+p.age);//10 main里的p仍是10
    }
}
class person{
    String name;
    int age;
}
class B{
    public void text200(Person p){
       p= new Person();//新建了一个新对象 指向新对象 这个对象会被当做垃圾回收
       p.name="tom";
       p.age=99;
}

克隆对象

//main函数
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);
//可以通过输出对象的hashCode看看对象是否是同一个
System.out.println(p==p2);//false

class Person {
    String name;
    int age;
}

class MyTools {
    
    public Person copyPerson(Person p) {
         //创建一个新对象
           Person p2=new Person();
           p2.name= p.name;//把原来对象的名字赋给p2.name
           p2.age=p.age;
           return p2;   
}

递归

递归就是方法自己调用自己,每次调用时传入不同的变量。

递归(recursion)执行机制

1、打印问题

//main方法
T t1=new T();
t1.test(4);//输出n=2 n=3 n=4

class T{
    public void test(int n){
    if(n>2){
        test(n-1);
}
Systm.out.println("n="+n);
    }
}
//方法执行完就回到被调用的语句
//main方法
T t1=new T();
t1.test(4);//只输出n=2 
class T{
    public void test(int n){
    if(n>2){
        test(n-1);
}else{
Systm.out.println("n="+n);
    }
}

每调用一次方法就新开一个栈

2、阶乘问题

T t1=new T();
int res=t1.factorial(5);
System.out.println("res="+res);//120
    }
}

class T{
   public int factorial(int n){
        if(n==1) {
            return 1;
            }else{
                return factorial(n-1)*n;
            }

递归总是从顶级的栈开始返回

递归重要规则

1、执行一个方法时,就创建一个新的受保护的独立空间(栈空间)。

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

3、如果方法中使用的是引用类型变量(比如数组,对象),就会共享该引用类型的数据。

4、递归必须向退出递归的条件逼近,否则就是无限递归,出现StackOverflowError,栈溢出。

5、当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁,同时当方法执行完毕或者返回时,该方法也就执行完毕(栈释放)。

方法重载(OverLoad)

java中允许同一个类中,多个同名方法的存在,但要求形参列表不一致。

例如:System.out.println();out是PrintStream类型

public class OverLoad01 {
    public static void main(String[] args){
        System.out.println(100);
        System.out.println("hello,world");
        System.out.println('h');
        System.out.println(1.1);
        System.out.println(true);
    }
}
MyCalculator mc=new MyCalculator();
System.out.println(mc.calculate(1,2));
System.out.println(mc.calculate(1.1,2));
    }
}

class MyCalculator {
//下面的四个calculate方法构成了重载

    public int calculate(int n1,int n2) {
        return n1+n2;
}
    public int calculate(int n1,double n2) {
        return n1+n2;
}    public int calculate(double n1,int n2) {
        return n1+n2;
}
    public int calculate(int n1,int n2,int n3) {
        return n1+n2+n3;
    }
}

注意事项和使用细节

1、方法名:必须相同。

2、形参列表:必须不同(形参类型/个数/顺序,至少有一样不同,参数名无要求)。

class MyCalculator {
//不构成重载,是方法的重复定义

    public int calculate(int n1,int n2) {
        return n1+n2;
}
    public int calculate(int a1,int a2) {
        return a1+a2;
}}

3、返回类型:无要求。

class MyCalculator {
//不构成重载,是方法的重复定义

    public int calculate(int n1,int n2) {
        return n1+n2;
}
    public void calculate(int n1,int n2) {
        int res=n1+n2;
}}

可变参数(variable parameters)

概念:java允许将同一个类中多个同名同功能参数个数不同的方法,封装成一个方法。就可以通过可变参数实现。

基本语法:

访问修饰符 返回类型 方法名(数据类型...形参名){

}

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 {
//1、int...表示接受的是可变参数,类型是int,即可以接收多个int(0-多)
//2、使用可变参数时,可以当作数组来使用,nums可以当作数组
//3、遍历nums求和即可
    public int sum(int... nums){
       // System.out.println("接收的参数个数="+nums.length);//3
        int res=0;
        for(int i=0;i<nums.length;i++) {
            res+=nums[i];
    }
        return res;
}

注意事项和细节

1、可变参数的实参可以为0个或任意多个。

2、可变参数的实参可以为数组。

public class VarParameterDetail {
    
    public static void main(String[] args) {
            int[] arr={1,2,3};
            T t1=new T();
            t1.f1(arr);
    }
}

class T{
    public void f1(int... nums){
        System.oout.println("长度="+nums.length);//3
        }
}

3、可变参数的本质就是数组。

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

public void f2(String str,double... nums) {

}

5、一个形参列表只能有一个可变参数。

例子:

public class VarParameterExercise {
    public static void main(String[] args){
        HspMethod hm =new HspMethod();
        System.out.println(hm.showScore("milan",90.1,80.0));
        System.out.println(hm.showScore("milan",90.1,80.0,70.0,70,30.5));
}
}

class HspMethod {
    public String showScore(String name,double... scores){
    double totalScore=0;
    for(int i=0;i<scores.length;i++){
        totalScore+=score[i];
}
return name+"有"+scores.length+"门课成绩总分为="+totalScore;
}
}

作用域(scope)

1、在java编程中,主要的变量就是属性(成员变量)和局部变量。

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

3、java中作用域的分类

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

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

4、全局变量可以不赋值,直接使用,因为有默认值,局部变量必须赋值后,才能使用,因为没有默认值。

public class VarScope {
    public static void main(String[] args){
    }
}
class Cat {
//属性在定义时,可以直接赋值
    int age=10;
    double weight;//默认值是0.0

{
    int num = 100;
}


public void cry(){
//n和name就是局部变量,局部变量必须赋值后,才能使用,没有默认值。
//n和name的作用域在 cry方法中
        int n=10;
        String name="jack";
System.out.println("在cry中使用属性 age="+ age);
}

public void eat(){
System.out.println("在eat中使用属性 age="+age);
}

注意事项和细节使用

1、属性和局部变量可以重名,访问时遵循就近原则

//main方法
Person p1=new Person();
p1.say();
    }
}

class Person {
    String name="jack";
    public void say(){
        String name="king';
        System.out.println("say()name="+name);//king
    }
}

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

3、属性生命周期较长,伴随着对象的创建而创建/销毁而销毁。

局部变量生命周期较短,伴随着它的代码块的执行而创建/结束而销毁,即在一次方法调用过程中。

例如:当执行say方法时,say方法的局部变量比如name会创建,当say执行完毕后name局部变量就销毁,但属性(全局变量)仍然可以使用。

4、作用域范围不同

全局变量/属性:可以被本类使用,或其它类使用(通过对象调用)。

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

例:两种方式

//main方法
Person p1=new Person();
T t1=new T();
t1.test();

    }
}

class T{
//全局变量/属性:可以被本类使用,或其它类使用(通过对象调用)。
    public void test(){
        System.out.println(p1.name);//jack
    }
    
class Person {
    String name="jack";
    public void say(){

}
    }
}
//main方法
Person p1=new Person();
T t1=new T();
t1.test2(p1);
    }
}

class T{
//全局变量/属性:可以被本类使用,或其它类使用(通过对象调用)。
public void test2(Person p) {
     System.out.println(p.name);//jack
}

class Person {
    String name="jack";
    public void say(){

}
    }
}

5、修饰符不同

全部变量/属性可以加修饰符

局部变量不可以加修饰符

class Person {
    private int age =20;//(属性)

    public void say(){
    String name="jack";//(局部变量)
}
}

构造器

例如:在创建人类的对象时,就直接指定这个对象的年龄和姓名。

基本语法:
【修饰符】方法名(形参列表){

                方法体;

}

1、构造器的修饰符可以默认,也可以是public,protected,private。

2、构造器没有返回值。

3、方法名和类名字必须一样

4、参数列表和成员方法一样的规则。

5、构造器的调用由系统完成。

基本介绍:

构造方法又叫构造器(constructor),是类的一种特殊的方法,主要作用:完成对新对象的初始化。(并不是去创建对象,对象的空间已经有了,具体的属性的值的初始化由构造器完成)

特点:

1、方法名和类名相同。

2、没有返回值。

3、在创建对象时,系统会自动的调用该类的构造器完成对对象的初始化

public class Constuctor01{
    public static void main(String[]  args){
//当我们new一个对象时,直接通过构造器指定名字和年龄
            Person p1= new Person("smith",80);
            System.out.println("p1的信息如下:");//②
            System.out.println("p1对象name=:"+p1.name);//③smith
            System.out.println("p1对象age=:"+p1.age);//④80
    }
}

class Person {
    String name;
    int age;
//构造器
//1、构造器没有返回值,也不能写void
//2、构造器的名称和类Person一样
//3、(String pName,int pAge)是构造器形参列表,规则和成员方法一样
    public Person(String pName,int pAge){
        System.out.println("构造器被调用,完成对象的属性初始化");//①
        name=pName;
        age=pAge;
    }
}

注意事项和使用细节

1、一个类可以定义多个不同的构造器,即构造器重载。

Person p1=new Person("king",40);
Person p2=new Person("tom");
    }
}

class Person{
    String name;
    int age;//默认0
//第一个构造器
    public Person(String pName,int pAge){
            name=pName;
            age=pAge;
}
//第二个构造器
    public Person(String pName) {
        name=pName;
}
}

2、构造器名和类名要相同。

3、构造器没有返回值。

4、构造器是完成对象的初始化,并不是创建对象。

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

6、如果程序员没有定义构造方法,系统会自动给类生成一个默认无参构造器(也叫默认构造器)。

Dog dog1= new Dog();
    }
}

class Dog{
/*默认构造器
    Dog(){
    
    }
*/
}

7、一旦定义了自己的构造器,默认的构造器就覆盖了,就不能再使用默认的无参构造器,除非显式的定义一下,即Dog(){}。

Person p1=new Person();
System.out.println("p1的信息 name="+p1.name +"age="+p1.age);//name=null; age=18;

Person p2=new Person("scott",50);
System.out.println("p2的信息 name="+p2.name +"age="+p2.age);//name=scott; age=50;
   }
}
class Person {
    String name;
    int age;

    public Person(){//无参构造器
        age=18;
}
    public Person(String pName,int pAge) {//带两个参数的构造器
                name=pName;
                age=pAge;
}
}

对象创建的流程分析

class Person{
    int age=90;
    String name;
Person(String n,int a){//构造器

    name=n;//把传进去的两个形参赋值给属性
    age=a;
}}
Person p=new Person("小亮",20);

对象在堆里面

p只能称为对象的引用/名字

·流程分析:

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

2、在堆中分配空间(地址)。

3、完成对象初始化(3.1默认初始化age=0 name=null 3.2显式初始化age=90 name=null 3.3构造器初始化 age=20 name=小亮)。

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

小总结

class 类名{

成员变量;

构造器;

成员方法;

}

this关键字

java虚拟机会给每个对象分配this,代表当前对象。

Dog dog1 =new Dog("大壮",3);
dog1.into();
Dog dog2 =new Dog("大黄",2);
dog2.into();

class Dog{

String name;
int age;

public Dog(String name,int age){//构造器
//this.name 当前对象的属性name
        this.name=name;
        this.age=age;
}
public void into(){//成员方法
    System.out.println(name +"\t" +age +"\t");//大壮 3 大黄 2
    }

}
 

this小结:哪个对象调用,this就代表哪个对象。

注意事项和细节

1、this关键字可以用来访问本类的属性、方法、构造器。

2、this用于区分当前类的属性和局部变量。

3、访问成员方法语法:this.方法名(参数列表);

//main方法
T t1=new T();
t1.f2();

class T {
    public void f1(){
        System.out.println("f1()方法..");
}
    public void f2(){
         System.out.println("f2()方法..");
         //调用本类的f1
         //法1
        f1();
        //法2
        this.f1();
}

4、访问构造器语法:this(参数列表);注意只能在构造器中使用(即只能在构造器中访问另外一个构造器)

访问构造器语法:this(参数列表);必须放置第一条语句

//main方法
T t2=new T();

class T {
    public T(){
         //这里去访问T(String name,int age)
        //访问构造器语法:this(参数列表);必须放置第一条语句
        this("jack",100);
        System.out.println("T()构造器");//②
       
}

    public T(String name,int age){
        System.out.println("T(String name,int age)构造器");//①
}
}

5、this不能在类定义的外部使用,只能在类定义的方法中使用。

//main
T t2=new T();
t2.f3();


class T{
    String name="jack";
    int num=100;

public void f3(){
String name="smith";
    System.out.println("name="+name +"num="+num);//若有局部变量要访问局部变量 smith 100
   //也可以这样
    System.out.println("name="+this.name +"num="+this.num);//准确的访问属性 jack 100
}
}


网站公告

今日签到

点亮在社区的每一天
去签到