面向对象与面向过程
总结:万物皆对象,把一个东西抽象成一个对象,描述这个东西的属性(特征),方法(行为)
类的定义
对象的创建和使用
person类:
public classPerson {//属性,成员变量,类的成员变量可以先声明,不用初始化,类成员变量是有默认值
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 classAnimal {
String name;//动物的名称
int eye;//眼睛的个数
int legs;//几条腿
/*** 输出动物吃的食物
*@paramfood 食物*/
public void eat(String food){//String food这个叫方法的参数,方法的参数可以有多个,参数之间用,分隔
System.out.println("此种动物的食物是:" +food);
}/*** 动物的移动方式
*@parammoveType 移动方式*/
public voidmove(String moveType){int i = 0;
System.out.println("此种动物的移动方式是:" +moveType);
}
}
View Code
创建完上面的类后,创建对象:
public classTest1 {public static voidmain(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 = newAnimal();
ani.eat("老鼠");
ani.move("飞");//未来可能会学习更加复杂的类,我们会给这类创建对象,并且使用对象,//对于对象的使用无外乎就两个地方,操作对象的变量,调用类方法
}
}
View Code
总结:
未来可能会学习更加复杂的类,我们会给这类创建对象,并且使用对象,
对于对象的使用无外乎就两个地方,操作对象的变量,调用类方法
类的属性
修饰符最大的好处:声明该属性的访问范围,保证了数据的安全性、隔离性、封装性。
比如当属性修饰符为private,其他类就无法访问该属性(私有的类变量不能通过对象.属性的方式调用),可以通过set和get方法声明该属性的读写权限。
当为public时,其他类也可以访问该属性,不能确保数据安全性,用户可以随时修改属性,造成异常。
例子:
public classPerson1 {
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
如果不了解代码块,详细:代码块
类的方法
例子:
练习:创建一个有属性/方法的学生类,并打印该学生信息。
importjava.util.Arrays;public classStudent {privateString name;private intage;private String [] course;//字符串数组
privateString[] hobbies;//无参构造
publicStudent() {}//有参构造器赋值
public Student(String name, intage, String[] course, String[] hobbies) {super();//这里可以直接去掉,因为不需要object父类的方法,如果要使用到父类的构造器就需要使用super()
this.name =name;this.age =age;this.course =course;this.hobbies =hobbies;
}//打印学生个人信息
publicString toString() {return "Student [name=" + name + ", age=" + age + ", course=" + Arrays.toString(course) + ", hobbies="
+ Arrays.toString(hobbies) + "]";
}public static voidmain(String[] args) {
String [] course= {"语文","数学"};//这里之所以创建一个数组,而不是直接在构造器中赋值,是因为语法不支持直接传递一个数组,必须间接传递一个数组变量
String [] hobbies = {"篮球","足球"};
Student student= new Student("zs",18,course,hobbies);
System.out.println(student.toString());
}
}
View Code
public classPerson {
String name;intage;
String sex;public voidstudy() {
System.out.println("studying");
}public voidshowAge() {
System.out.println("age:"+age);
}//传递多少岁数,就加多少
public int addAge(inti) {return age+=i;
}public static voidmain(String[] args) {
Person person1= newPerson();
Person person2= newPerson();
System.out.println(person1== person2);//false 不同对象之间就算属性方法一致,内存地址始终不一样,每new一次都会给一个对象分配内存空间
}
}
View Code
public classCircle {//计算圆的面积公式 : 3.14*r*r
/***
*@paramr圆的半径
*@return返回圆面积*/
public double area(doubler) {return 3.14*r*r;
}public static voidmain(String[] args) {//使用匿名对象调用方法
System.out.println(new Circle().area(2));
}
}
View Code
例如:
方法的重载
例子:
public classAdd {//多个相同名称的方法如果在一个类中共存,那么这些同名方法一定是参数的个数/数据类型不相同//这样的同名方法就叫做 方法的重载//重载机制:调用重载方法时,根据传递的参数列表(参数个数/数据类型)决定调用哪个重载方法,而不是根据返回值类型
public int add(int x ,inty) {return x+y;
}public int add(int x ,int y,intz) {return x+y+z;
}public double add(double x , doubley) {return x+y;
}public double add(double x , double y, doublez) {return x+y+z;
}public static voidmain(String[] args) {
Add add= newAdd();
add.add(1.1, 2.3);//这里调用的是两个double类型的重载方法
}
}
View Code
public classMol {public int mOL(inti) {return i*i;
}public int mOL(int i , intj) {return i*j;
}publicString mOL(String i) {returni;
}public static voidmain(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 classMax {public int max(int i ,intj) {if(i >j) {returni;
}else{returnj;
}
}public double max(double i ,doublej) {if(i >j) {returni;
}else{returnj;
}
}public double max(double i ,double j,doublez) {if(i >j) {if(i >z) {returni;
}else{returnz;
}
}else{if(j >z) {returni;
}else{returnz;
}
}
}public static voidmain(String[] args) {
Max max= newMax();
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 classPerson3 {/*** 用数组的方式来传递可变个数的参数
*@paramargs*/
public void printInfo(String[] args) {//问题,我们能够打印的信息都有源于方法的参数也就是形参的传递//我们现在可能给方法要传递不同的参,但是我们不知道要给方法传递多少个参数(姓名/性别/年龄等等)
for(int i = 0 ; i < args.length ; i++) { //方法一:可以定义一个数组接收可变参数,然后遍历参数
System.out.println(args[i]);
}
}/*** 用java特有的...的方式来传递可变个数的参数,这种参数在使用时和数组的使用方式相同
*@paramargs*/
//java自带自定义参数格式: 数据类型... 变量名 ,如果还有其他参数,那么自定义参数必须放在最后声明//例如:(String... args,int i)这种会报错,自定义参数必须放在最后声明 应为:(int i , String... args)才对
public voidprintInfo1(String... args) {for(int i = 0 ; i < args.length ; i++) { //方法二:可以定义一个 自定义参数列表 来接收可变参数,然后遍历参数
System.out.println(args[i]);
}
}public static voidmain(String[] args) {
Person3 person= newPerson3();
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 classTest2 {public intage;private intlegs;public voidprintAge() {
System.out.println("年龄:"+age);
}//可以把属性设置为私有化,通过set方法定义属性的范围,限制不正常的输入
public void setLegs(intlegs) {if(legs >=0 && legs < 10) {this.legs =legs;
}else{
System.out.println("输入的腿的数量不正常");
}
}//如果限制了用户属性,但是又要使用这个属性,可以设置get方法给用户获取该属性
public intgetLegs() {returnlegs;
}public static voidmain(String[] args) {
Test2 test= newTest2();
test.age=-100;//这种情况,程序是对的,能执行,但不符合正常逻辑//像这种情况,是把类的属性开发出来,让调用者随意使用,这样会有问题
test.printAge();
test.setLegs(-100);//限制了用户乱调用数据
test.setLegs(4);
System.out.println(test.getLegs());//获取封装的属性
}
}
View Code
访问权限修饰符
//Person类
public classPerson {private intage;public void setAge(intage) {if(age > 0 && age <=130) {this.age =age ;
}else{
System.out.println("年龄不合法");
}
}public intgetAge() {returnage;
}
}//TestPerson类
public classTestPerson {public static voidmain(String[] args) {
Person person= newPerson();
person.setAge(-12);
person.setAge(20);
System.out.println(person.getAge());
}
}
View Code
类的构造器(构造方法)
public classPerson1 {private intage;/*** 如果定义了显式构造方法,那么new对象时就使用显示构造方法
* 如果定义了显示带参构造方法,不定义无参构造方法时,new Person1()这样就会报错,因为显示构造方法已经代替了默认的构造方法
* 所以如果定义了带参构造方法,最好定义多一个无参构造
**/
public Person1() {}//如果不定义有参构造方法,这个就是隐藏的构造方法,new对象时,调用这个方法
public Person1(int age) {//有参构造,创建对象时,就可以直接调用有参构造,因为这里定义了有参构成,所以需要重新定义无参构造
this.age = age; //this.age指当前类的age属性,后面的age是形参
}public static voidmain(String[] args) {//new对象的根本原理:就是通过类的构造方法
Person1 pe = new Person1();//new Person2()对象调用的是public Person1(){}方法,不过这个方法是隐藏的,默认构造器修饰符是根据类修饰符决定
}
}classPerson2{//Person2() {}//Person2类前面修饰符是默认的,构造方法修饰符就是默认的
public static voidmain(String[] args) {
Person2 pe= new Person2();//new Person2()对象调用的是Person2(){}方法
}
}
View Code
总结:new对象其实就是调用类的构造方法
public classPerson {private intage;privateString name;public Person() {//定义默认构造器,初始年龄18
age = 18;
}public Person(int age,String name) {//定义有参构造
this.age =age;this.name =name;
}public static voidmain(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 classPoint {private intx,y,z;public Point(int x,int y,intz) {this.x =x;this.y =y;this.z =z;
}public void setPoint(int x, int y, intz) {this.x =x;this.y =y;this.z =z;
}public static voidmain(String[] args) {
Point p= new Point(1, 2, 3);//生成具有特定坐标的点对象
p.setPoint(6, 7, 8);//提供了设置3个坐标的方法
}
}
View Code
//TriAngle类
public classTriAngle {private int base;//底边长
private int height;//高
publicTriAngle() {}public TriAngle(int base,intheight) {this.base =base;this.height =height;
}public intbase() {returnbase;
}public intheight() {returnheight;
}
}//TestTriAngle类
public classTestTriAngle {public static voidmain(String [] args) {
TriAngle angle= new TriAngle(5,5);//初始化底边和高//三角形的面积公式
double area = (angle.base()*angle.height())/2.0;
System.out.println(area);
}
}
View Code
this关键字
View Code
实体类JavaBean
public classPerson8 {privateString name;privateString sex;private intage;privateString hobbies;publicString getName() {returnname;
}public voidsetName(String name) {this.name =name;
}publicString getSex() {returnsex;
}public voidsetSex(String sex) {this.sex =sex;
}public intgetAge() {returnage;
}public void setAge(intage) {this.age =age;
}publicString getHobbies() {returnhobbies;
}public voidsetHobbies(String hobbies) {this.hobbies =hobbies;
}
@OverridepublicString toString() {return "Person8 [name=" + name + ", sex=" + sex + ", age=" + age + ", hobbies=" + hobbies + "]";
}
}
View Code
总结:JavaBean就是一个实体类,把属性/方法封装好,提供了设置和获取属性的方法(get/set方法),get和set方法可以自动生成,在创建完属性之后,鼠标右键选择Source>Gengerate Getter and Setter自动创建。