java的面向对象概念、封装特性

 

 

 

 

 总结:万物皆对象,把一个东西抽象成一个对象,描述这个东西的属性(特征),方法(行为)

 

 

 person类:

public class Person {
    //属性,成员变量,类的成员变量可以先声明,不用初始化,类成员变量是有默认值
    String name;//姓名,String的默认值是null
    int age;//年龄,int的默认值是0
    
    //行为,方法,也叫函数
    /**
     * 打印姓名
     */
    public void showName(){//方法的名称如果是多个单词,首个的单词的首字母小写,其他的单词首字母大写,这样就像一个驼峰一样,所有叫驼峰命名法
        System.out.println("姓名:" + name);
        getAge();//同一个类中,所有的方法可以直接互相调用,不用new去实例化对象
//        public void xx(){}//方法中不能再定义方法
    }
    /**
     * 获取年龄
     * @return
     */
    public int getAge(){//如果是一个有返回值的方法,那么方法体的最后一行一定是返回相应的数据,使用return关键字,返回的数据类型与方法定义的一致
        return age;//方法上定义的int是返回值的类型,return后面跟的是方法的返回值
    }
}
View Code

Animal类:

public class Animal {
    String name;//动物的名称
    int eye;//眼睛的个数
    int legs;//几条腿
    
    /**
     * 输出动物吃的食物
     * @param food 食物
     */
    public void eat(String food){//String food这个叫方法的参数,方法的参数可以有多个,参数之间用,分隔
        System.out.println("此种动物的食物是:" + food);
    }
    
    /**
     * 动物的移动方式
     * @param moveType 移动方式
     */
    public void move(String moveType){
        int i = 0;
        System.out.println("此种动物的移动方式是:" + moveType);
    }
}
View Code

创建完上面的类后,创建对象:

public class Test1 {
    public static void main(String[] args){
//        //实例化Person类,也就是创建Person对象
        Person person = new Person();//声明一个Person类型的变量,变量名person,实例化Person类并且给person赋值,赋值的值就是当前的实例
//        //new Person()就是实例化Person类
        person.name = "张三";//给person对象的name属性赋值
        person.showName();//对象的方法的调用
        int i = person.getAge();//有返回值的方法,在调用之后就会有一个值,这个值就是方法中return的那部分
        System.out.println(i);//打印默认年龄

        person.age = 11;//给person对象的age属性赋值
        int a = person.getAge();
        System.out.println(a);
        
        //实例化一个Animal的对象
        Animal ani = new Animal();
        
        ani.eat("老鼠");
        
        ani.move("飞");
        
        //未来可能会学习更加复杂的类,我们会给这类创建对象,并且使用对象,
        //对于对象的使用无外乎就两个地方,操作对象的变量,调用类方法
    }
}
View Code

总结

未来可能会学习更加复杂的类,我们会给这类创建对象,并且使用对象,
对于对象的使用无外乎就两个地方,操作对象的变量,调用类方法

 

 修饰符最大的好处:声明该属性的访问范围,保证了数据的安全性、隔离性、封装性。

比如当属性修饰符为private,其他类就无法访问该属性(私有的类变量不能通过对象.属性的方式调用),可以通过set和get方法声明该属性的读写权限。

当为public时,其他类也可以访问该属性,不能确保数据安全性,用户可以随时修改属性,造成异常。

 例子:

public class Person1 {
    Person person = new Person();//在类中可以创建对象,但是访问不了该对象的属性
//    person.name;//这种方式报错,访问不了属性,没找到原因,name是public修饰的
    {
        String name = "?";//代码块局部变量  1
    }
    static String names = "?";//这种就是类变量(也称为静态变量)可以  类名.变量名使用,也是成员变量 2
    
    public static void main(String[] args) {//这里的args就是形参,也是局部变量1
        int i = 0; //这里的i就是方法体   局部变量 1
        Person person = new Person();//实例化对象 
        person.name = "?"; //实例变量,只能实例化对象后才能使用,也是成员变量 2
    }
}
View Code

如果不了解代码块,详细:代码块

 

 

 

 例子:

练习:创建一个有属性/方法的学生类,并打印该学生信息。

import java.util.Arrays;

public class Student {
    private String name;
    private int age;
    private String [] course;//字符串数组
    private String[] hobbies;

    //无参构造
    public Student() {}
    //有参构造器赋值
    public Student(String name, int age, String[] course, String[] hobbies) {
        super();//这里可以直接去掉,因为不需要object父类的方法,如果要使用到父类的构造器就需要使用super()
        this.name = name;
        this.age = age;
        this.course = course;
        this.hobbies = hobbies;
    }
    
    //打印学生个人信息
    public String toString() {
        return "Student [name=" + name + ", age=" + age + ", course=" + Arrays.toString(course) + ", hobbies="
                + Arrays.toString(hobbies) + "]";
    }
    
    public static void main(String[] args) {
        String [] course = {"语文","数学"};//这里之所以创建一个数组,而不是直接在构造器中赋值,是因为语法不支持直接传递一个数组,必须间接传递一个数组变量
        String [] hobbies = {"篮球","足球"};
        Student student = new Student("zs",18,course,hobbies);
        System.out.println(student.toString());
    }
}
View Code

 

 

 

 

public class Person {
    String name;
    int age;
    String sex;
    
    public void study() {
        System.out.println("studying");
    }
    
    public void showAge() {
        System.out.println("age:"+age);
    }
    //传递多少岁数,就加多少
    public int addAge(int i) {
        return age+=i;
    }
    
    public static void main(String[] args) {
        Person person1 = new Person();
        Person person2 = new Person();
        System.out.println(person1 == person2);//false  不同对象之间就算属性方法一致,内存地址始终不一样,每new一次都会给一个对象分配内存空间
    }
}
View Code

public class Circle {
    //计算圆的面积公式 : 3.14*r*r
    /**
     * 
     * @param r圆的半径
     * @return 返回圆面积
     */
    public double area(double r) {
        return 3.14*r*r;
    }
    public static void main(String[] args) {
        //使用匿名对象调用方法
        System.out.println(new Circle().area(2));
    }
}
View Code

 例如:

 

 

例子:

public class Add {
    
    //多个相同名称的方法如果在一个类中共存,那么这些同名方法一定是参数的个数/数据类型不相同
    //这样的同名方法就叫做    方法的重载
    //重载机制:调用重载方法时,根据传递的参数列表(参数个数/数据类型)决定调用哪个重载方法,而不是根据返回值类型
    public int add(int x ,int y) {
        return  x+y;
    }
    public int add(int x ,int y,int z) {
        return  x+y+z;
    }
    
    public double add(double x , double y) {
        return  x+y;
    }
    public double add(double x , double y, double z) {
        return  x+y+z;
    }
        
    public static void main(String[] args) {
        Add add = new Add();
        add.add(1.1, 2.3);//这里调用的是两个double类型的重载方法
    }
}
View Code

 

 

public class Mol {
    public int mOL(int i) {
        return i*i;
    }
    
    public int mOL(int i , int j) {
        return i*j;
    }
    
    public String mOL(String i) {
        return i;
    }
    
    public static void main(String[] args) {
        Mol mol = new Mol();//实例化对象
        System.out.println(mol.mOL(4));
        System.out.println(mol.mOL(4,2));
        System.out.println(mol.mOL("方法重载"));
        //这里说明一下关于同一类中不用实例化也可以调用其他方法
        //那为什么在main里面要new一个对象才能用其他方法呢
        //因为main方法有static修饰符,静态方法不可访问非静态方法
        //同理,非静态方法只能调用非静态方法,不能调用静态方法
        //如果想静态方法调用非静态方法,可以实例化对象,然后直接对象.方法调用
    }
}
View Code

public class Max {
    public int max(int i ,int j) {
        if(i > j) {
            return i;
        }
        else {
            return j;
        }
    }
    
    public double max(double i ,double j) {
        if(i > j) {
            return i;
        }
        else {
            return j;
        }
    }
    
    public double max(double i ,double j,double z) {
        if(i > j) {
            if(i > z) {
                return i;
            }
            else {
                return z;
            }
        }
        else {
            if(j > z) {
                return i;
            }
            else {
                return z;
            }
        }
    }
    
    public static void main(String[] args) {
        Max max = new Max();
        System.out.println(max.max(4,3));
        System.out.println(max.max(4.1,3.6));
        System.out.println(max.max(4.12,3.32,2.23));
    }
}
View Code

 

 例子:

public class Person3 {
    /**
     * 用数组的方式来传递可变个数的参数
     * @param args
     */
    public void printInfo(String[] args) {//问题,我们能够打印的信息都有源于方法的参数也就是形参的传递
        //我们现在可能给方法要传递不同的参,但是我们不知道要给方法传递多少个参数(姓名/性别/年龄等等)
         for(int i = 0 ; i < args.length ; i++) { //方法一:可以定义一个数组接收可变参数,然后遍历参数
             System.out.println(args[i]);
         }
    }
    
    /**
     * 用java特有的...的方式来传递可变个数的参数,这种参数在使用时和数组的使用方式相同
     * @param args
     */
    //java自带自定义参数格式: 数据类型... 变量名 ,如果还有其他参数,那么自定义参数必须放在最后声明
    //例如:(String... args,int i)这种会报错,自定义参数必须放在最后声明    应为:(int i , String... args)才对
    public void printInfo1(String... args) {
         for(int i = 0 ; i < args.length ; i++) { //方法二:可以定义一个  自定义参数列表    来接收可变参数,然后遍历参数
             System.out.println(args[i]);
         }
    }
    
    public static void main(String[] args) {
        Person3 person = new Person3();
        String[] ss = new String[]{"zhangsan","38"};
        person.printInfo(ss);
        person.printInfo1(ss);//这两种输出结果一致
        //这两种区别在于   传递参数是否可为null,数组如果不传递参数,需要传递一个null,而自带自定义参数列表不用传递任何值
//        person.printInfo();//这里会报错,这里是数组,如果不传递参数时,必须传递一个null或空数组
        person.printInfo1();//这里是自带的  自定义参数列表
    }
}
View Code

 

 创建对象的内存分配过程:Person p = new  Person(); p在栈中存储,而p存储着new Person()的内存地址,new Person()是存储在堆里面。内存地址起到了间接引用的作用。

 

 方法的参数传递总结:

1、如果方法的形参是基本数据类型,那么实参(实际的数据)向形参传递参数时,就是直接传递值,把实参的值复制给形参。

2、如果方法的形参是对象/引用类型,那么实参(实际的对象),向形参传递参数时,也是把值给形参,不过这个值是实参在栈内存中的值,也就是引用对象在堆内存中的地址

基本数据类型都是保存在栈内存中,引用对象在栈内存中保存的是引用对象的堆地址,那么方法的参数传递是传递值(是变量在栈内存中的值)

 简单来说,就是栈存储的值有两种,一种是基本数据类型的值,一种是堆内存的地址。修改基本数据的值不会影响原来传递的实参的值,但是如果是对象/引用类型如果修改了传递对象的属性/方法,那么就会影响到原来传递的实参的对象,因为原来的实参和传递过去的形参指向同一对象的堆内存地址,也就是使用的同一对象。

 

 如果类中的属性定义为public那么属性任由调用者使用,会造成数据混乱,应该把数据封装起来

 例子:这里用了同一类示范,假设是main方法是其他类的,这样就访问不了private私有属性,只能通过set/get方法访问

public class Test2 {
    public int age;
    private int legs;
    
    public void printAge() {
        System.out.println("年龄:"+age);
    }
    
    //可以把属性设置为私有化,通过set方法定义属性的范围,限制不正常的输入
    public void setLegs(int legs) {
        if(legs >=0 && legs < 10) {
            this.legs = legs;
        }
        else {
            System.out.println("输入的腿的数量不正常");
        }
    }
    //如果限制了用户属性,但是又要使用这个属性,可以设置get方法给用户获取该属性
    public int getLegs() {
        return legs;
    }
    
    public static void main(String[] args) {
        Test2 test = new Test2();
        test.age=-100;//这种情况,程序是对的,能执行,但不符合正常逻辑
        //像这种情况,是把类的属性开发出来,让调用者随意使用,这样会有问题
        test.printAge();
        test.setLegs(-100);//限制了用户乱调用数据  
        test.setLegs(4);
        System.out.println(test.getLegs());//获取封装的属性
    }
}    
View Code

 

//Person类
public class Person {
    private int age;
    
    public void setAge(int age) {
        if(age > 0 && age <=130) {
            this.age = age ;
        }
        else {
            System.out.println("年龄不合法");
        }
    }
    
    public int getAge() {
        return age;
    }
}


//TestPerson类
public class TestPerson {
    public static void main(String[] args) {
        Person person = new Person();
        person.setAge(-12);
        person.setAge(20);
        System.out.println(person.getAge());
    }
}
View Code

 

public class Person1 {
    private int age;
    /**
     * 如果定义了显式构造方法,那么new对象时就使用显示构造方法
     * 如果定义了显示带参构造方法,不定义无参构造方法时,new Person1()这样就会报错,因为显示构造方法已经代替了默认的构造方法
     * 所以如果定义了带参构造方法,最好定义多一个无参构造
     * 
     */
    public Person1() {}//如果不定义有参构造方法,这个就是隐藏的构造方法,new对象时,调用这个方法
    public Person1(int age) {//有参构造,创建对象时,就可以直接调用有参构造,因为这里定义了有参构成,所以需要重新定义无参构造
        this.age = age;  //this.age指当前类的age属性,后面的age是形参
    }
    
    public static void main(String[] args) {
        //new对象的根本原理:就是通过类的构造方法
        Person1 pe = new Person1();//new Person2()对象调用的是public Person1(){}方法,不过这个方法是隐藏的,默认构造器修饰符是根据类修饰符决定
    }
}

class Person2{
//   Person2() {} //Person2类前面修饰符是默认的,构造方法修饰符就是默认的
    
    public static void main(String[] args) {
        Person2 pe = new Person2();//new Person2()对象调用的是Person2(){}方法
    }
}
View Code

 

 总结:new对象其实就是调用类的构造方法

public class Person {
    private int age;
    private String name;
    
    public Person() {//定义默认构造器,初始年龄18
        age = 18;
    }
    
    public Person(int age,String name) {//定义有参构造
        this.age = age;
        this.name = name;
    }
    
    public static void main(String[] args) {
        Person p = new Person();//调用无参构造
        Person p1 = new Person(13,"猪头");//调用有参构造
        System.out.println(p.age);
        System.out.println(p1.age+","+p1.name);
    }
}
View Code

public class Point {
    private int x,y,z;
    
    public Point(int x,int y,int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    
    public void setPoint(int x, int y, int z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    public static void main(String[] args) {
        Point p = new Point(1, 2, 3);//生成具有特定坐标的点对象
        p.setPoint(6, 7, 8);//提供了设置3个坐标的方法
    }
}
View Code

//TriAngle类
public class TriAngle {
    private int base;//底边长
    private int height;//
    
    public TriAngle() {}
    public TriAngle(int base,int height) {
        this.base = base;
        this.height = height;
    }
    public int base() {
        return base;
    }
    public int height() {
        return height;
    }
}


//TestTriAngle类
public class TestTriAngle {
    public static void main(String [] args) {
        TriAngle angle = new TriAngle(5,5);//初始化底边和高
        //三角形的面积公式
        double area = (angle.base()*angle.height())/2.0;
        System.out.println(area);
    }
}
View Code

View Code

 

 

 

public class Person8 {
    private String name;
    private String sex;
    private int age;
    private String hobbies;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getHobbies() {
        return hobbies;
    }
    public void setHobbies(String hobbies) {
        this.hobbies = hobbies;
    }
    @Override
    public String toString() {
        return "Person8 [name=" + name + ", sex=" + sex + ", age=" + age + ", hobbies=" + hobbies + "]";
    }
    
}
View Code

总结:JavaBean就是一个实体类,把属性/方法封装好,提供了设置和获取属性的方法(get/set方法).

猜你喜欢

转载自www.cnblogs.com/unlasting/p/12373779.html