java的面相对象感觉很有活力比python那种简便化的面相对象有趣多了,何谓面相对象什么是面向对象,这个话题一直是很多人和面试官会去深究的问题,,
面向对象思想是将人们在现实生活中的事物应用到程序设计中。对象就是现实生活中真实存在的,比如某个人某个事物这都是可以叫做一个对象
类:
将具有相同属性及相同行为的一组对象称为类。广义地讲,具有共同性质的事物 的集合就称为类。
eg:一匹马是一个类。而马就是对象。类可以理解为这个对象中的一个实例而对象是一个大的泛指
面向对象的程序设计有三个主要特征,如下:
封装性 继承性 多态性
首先先创建一个简单的类和对象
public class clas { public static void main(String[] args) { // 首先想要调用类中的信息要先是实例化一个对象类操作 Person p1 = new Person(); //然后通过对象给类中的信息赋值 p1.name = "隔壁老王"; p1.age = 17; p1.talk(); // 我是隔壁老王今年:17 } } class Person{ //类 String name; //属性 int age; boolean isMarried; public void walk(){ // 方法 System.out.println("人走路"); } public void eat(){ System.out.println("人能吃"); } void talk(){ System.out.println("我是"+name+"今年:"+age); } }
类中的方法是通过void来进行实现的。和python的def差不多
创建对象语法: 类名 对象名 = new 类名();
创建类中的方法一般需要加上void : void 方法名(){方法体}
注意:在整个java项目(java文件)中不可以出现相同的类,因为java在编译的时候上面的类编译之后 再识别出相同的就会报错,或者在倒入的时候也会导致识别出错
一个类可以有多个对象,实例化的对象的空间每一个都在内存中单独开辟一块空间互不干扰
如果类中有私有属性 private装饰的就不能直接调用或者赋值了不然就会报错
成员变量存储在堆中 是需要垃圾回收机制来处理,局部变量存储在栈中随着方法的结束而释放
练习:
编写教师类和学生类,并通过测试类创建对象进行测试 Student类 属性: name:String age:int major:String interests:String 方法:say() 返回学生的个人信息 Teacher类 属性: name:String age:int teachAge:int course:String 方法:say() 输出教师的个人信息
eg:
public class cls { public static void main(String[] args) { teacher te = new teacher(); te.name = "王老师"; te.age = 17; stu st = new stu(); st.name = "小明"; st.age = 16; te.say(st.name,st.age); st.say(te.name, te.age); } } class teacher{ // 老师类 String name; int age; String major; String interests; void say(String name, int age){ System.out.println("这个学生是:"+name+"年龄是:"+age); } } class stu{ // 学生类 String name; int age; int teacherAge; String course; void say(String name, int age){ System.out.println("这个老师是:"+name+"年龄是:"+age); } }
方法的声明:
权限修饰符 返回值类型 方法名(形参列表){ 方法体 } 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
注意:我们再传递参数的时候也一定要把参数的类型传递进去不然会报错 public void addAge(int age){ // 传递参数把参数age的类型int也传递进去 age +=2; }
return :java中的return和python的return是一样的。都是返回结果 然后终止方法
方法可以分为void不带返回值的方法 和携带返回值的方法
class te{ String name; // 成员变量 int age; String major; void sys(){ // void不需要返回值 int age; } public String getName(){ return name; // 因为方法体是没有void的就需要return来进行返回了 } }
注意:
在方法中可以调用方法:递归调用
但是不可以在方法中定义方法
练习:
1、
编写程序,声明一个method方法,在方法中打印一个10*8 的*型矩形,在main方法中调用该方法
public class Usertest { public static void main(String[] args) { Usertest user = new Usertest(); user.method(); } public void method(){ for(int i = 0; i < 10; i++ ){ for(int j = 0; j < 8; j++){ System.out.print("*"); } System.out.println(); } } }
2、
修改上一个程序,在method方法中,除打印一个10*8的*型矩形外,再计算该矩形的面积,
* 并将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
public class Usertest { public static void main(String[] args) { Usertest user = new Usertest(); int aray = user.method(); System.out.println("矩形的面积是:"+aray); } public int method(){ for(int i = 0; i < 10; i++ ){ for(int j = 0; j < 8; j++){ System.out.print("*"); } System.out.println(); } return 10*8; // 想要返回值就要把上面的方法定义为要放回值的类型 } }
3、
修改上一个程序,在method方法提供m和n两个参数,方法中打印一个m*n的*型矩形,
* 并计算该矩形的面积, 将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
public class Usertest { public static void main(String[] args) { Usertest user = new Usertest(); int aray = user.method(10,5); // 给参数 System.out.println("矩形的面积是:"+aray); } public int method(int m, int n){ // 传递参数 for(int i = 0; i < m; i++ ){ for(int j = 0; j < n; j++){ System.out.print("*"); } System.out.println(); } return 10*8; // 想要返回值就要把上面的方法定义为要放回值的类型 } }
对象数组题目
对象数组题目: 定义类Student,包含三个属性:学号number(int),年级state(int),成绩 score(int)。 创建20个学生对象,学号为1到20,年级和成绩都由随机数确定。
问题一:打印出3年级(state值为3)的学生信息。
问题二:使用冒泡排序按学生成绩排序,并遍历所有学生信息 提示: 1) 生成随机数:Math.random(),返回值类型double; 2) 四舍五入取整:Math.round(double d),返回值类型long。 5.声明一个日期类型MyDate:有属性:年year,月month,日day。创建2个日期 对象,分别赋值为:你的出生日期,你对象的出生日期,并显示信息。
第一种:
public class Usertest{ public static void main(String[] args) { Stude [] stu = new Stude [20]; // 生成一个对象数组规定长度为20 因为要生成20个不能一个一个生成吧 for(int i = 0; i < stu.length; i++){ stu[i] = new Stude (); // 生成每一个对象的数组 // 给每一个对象属性赋值 stu[i].number = (i+1); //年纪[1, 6] stu[i].state = (int)(Math.random()*(6-1+1)+1); stu[i].score = (int)(Math.random()*(100-0-1)+1); } // 遍历学生数组 for(int i = 0; i < stu.length; i++){ // System.out.println(stu[i].number+","+stu[i].state+","+stu[i].score); System.out.println(stu[i].info()); } System.out.println(); // 求出三年级学生的的学生信息 System.out.println("这是三年级学生的信息"); for(int i = 0; i < stu.length; i++){ if(stu[i].state == 3){ System.out.println(stu[i].info()); } } System.out.println("========="); // 使用冒泡排序对学生的成绩排序 for(int i = 0; i < stu.length;i++){ for(int j = 0; j < stu.length -i -1; j++){ if(stu[j].score > stu[j+1].score){ // 两个值的转换必须要定义一个第三方数字不能像python一直直接交换 Stude tmp = stu[j]; // 参数的定义也要是对象数组的元素 stu[j] = stu[j+1]; stu[j+1] = stu[j]; } } } for(int i = 0; i < stu.length; i++){ // System.out.println(stu[i].number+","+stu[i].state+","+stu[i].score); System.out.println(stu[i].info()); } } static class Stude{ // 因为主类是static的 如果写在了公类里面 也要是static,除非是放在公类外部 int number = 0; // 学号 int state = 0; // 年纪 int score = 0; // 成绩 String info(){ return "学号:"+number+" 年纪: "+state+" 成绩: "+score; } } }
第二种面向对象的额封装:
public class Usertestplus { public static void main(String[] args) { Student [] stu = new Student[20]; for(int i = 0; i < stu.length; i++){ stu[i] = new Student(); // 实例化每一个对象 //为每一个对象的信息进行赋值 stu[i].number = i+1; stu[i].state = (int)(Math.random()*(6-1+1)+1); stu[i].score = (int)(Math.random()*(100 -0 +1)+1); } // 因为方法是在公共类中的 需要公共类的对象来调用 Usertestplus user = new Usertestplus(); user.print(stu); //打印3年纪的学生的信息 System.out.println("打印3年纪学生的信息"); user.searchState(stu,3); //使用冒泡排序来进行信息排序 System.out.println("使用冒泡进行排序"); user.sort(stu); // 对排序后的 信息进行遍历 user.print(stu); } // 遍历信息 static void print(Student[] stu){ // 把定义的类数组给传递进来 for(int i = 0; i < stu.length; i++){ System.out.println(stu[i].info()); } } //查找 3年纪的学生的信息 static void searchState(Student [] stu, int state){ for(int i = 0 ;i < stu.length; i++){ if(stu[i].state == state){ System.out.println(stu[i].info()); } } } //排序 static void sort(Student [] stu){ for(int i = 0; i<stu.length; i++){ for(int j = 0; j < stu.length-i-1; j++){ if(stu[j].score > stu[j+1].score){ Student tmp = stu[j]; stu[j]= stu[j+1]; stu[j+1] = tmp; } } } } } class Student{ int number; //学号 int state; // 年纪 int score; // 成绩 public String info(){ return "学号:"+number+" 年纪:"+state+" 成绩:"+score; } }
对象的内存解析:
匿名对象:
即没有对这个对象赋名。每一次使用都要new一个
Person p1 = new Person(); //然后通过对象给类中的信息赋值 p1.name = "隔壁老王"; p1.age = 17; p1.talk(); // 我是隔壁老王今年:17 //上面是创建了有名对象每次使用都通过这个对象名去调用 // 匿名对象: new Person().age=16; // 通过匿名对象去调用 new Person().name = "老李";// 这两个匿名对象是不同的
每一次创建的匿名对象是不同的:
public class clas { public static void main(String[] args) { // 首先想要调用类中的信息要先是实例化一个对象类操作 Person p1 = new Person(); //然后通过对象给类中的信息赋值 p1.name = "隔壁老王"; p1.age = 17; p1.talk(); // 我是隔壁老王今年:17 //上面是创建了有名对象每次使用都通过这个对象名去调用 // 匿名对象: new Person().age=16; // 通过匿名对象去调用 new Person().name = "老李";// 这两个匿名对象是不同的 new Person().talk(); // 我是null今年:0 这里的值是都不同的 所以对象都是不同的 } } class Person{ String name; int age; boolean isMarried; public void walk(){ System.out.println("人走路"); } public void eat(){ System.out.println("人能吃"); } void talk(){ System.out.println("我是"+name+"今年:"+age); } }
方法的重载:即一个类中可以出现多个名字相同的方法 只要参数的个数或者类型不同即可,甚至两个参数的位置不同的 时候也会认为是两个不同的方法
String name; int age; boolean isMarried; public void walk(){ System.out.println("人走路"); } public void eat(){ System.out.println("人能吃"); } //如下的两个方法构成了方法的重载 void talk(){ System.out.println("我是"+name+"今年:"+age); } void talk(int age){ System.out.println(age); } }
判断是否是重载:
跟方法的权限修饰符、返回值类型、行参变量名、方法体都没有关系
习题:判断是否是重载
与void show(int a,char b,double c){}构成重载的有:
a) void show(int x,char y,double z){} // no b) int show(int a,double c,char b){} // yes c) void show(int a,double c,char b){} // yes d) boolean show(int c,char b){} // yes e) void show(double c){} // yes f) double show(int x,char y,double z){} // no
g) void shows(){double c} // no
练习:
编写程序,定义三个重载方法并调用。方法名为mOL。 三个方法分别接收一个int参数、两个int参数、一个字符串参数。分别
执行平方运算并输出结果,相乘并输出结果,输出字符串信息。 在主类的main ()方法中分别用参数区别调用三个方法。
3.定义三个重载方法max(),第一个方法求两个int值中的最大值,第二个方 法求两个double值中的最大值,第三个方法求三个double值中的最大值, 并分别调用三个方法
public class clas { public static void main(String[] args) { // 首先想要调用类中的信息要先是实例化一个对象类操作 Person p1 = new Person(); //然后通过对象给类中的信息赋值 p1.name = "隔壁老王"; p1.age = 17; p1.talk(); // 我是隔壁老王今年:17 //上面是创建了有名对象每次使用都通过这个对象名去调用 // 匿名对象: new Person().age=16; // 通过匿名对象去调用 new Person().name = "老李";// 这两个匿名对象是不同的 new Person().talk(); // 我是null今年:0 这里的值是都不同的 所以对象都是不同的 // System.out.println(p1.mOl(3)); // 9 System.out.println(p1.mOl(3,6)); // 18 System.out.println(p1.mOl("lao")); // 这个是:lao System.out.println(p1.max(3,7)); //7 System.out.println(p1.max(3.2,5.64)); //5。64 } } class Person{ String name; int age; boolean isMarried; public void walk(){ System.out.println("人走路"); } public void eat(){ System.out.println("人能吃"); } //如下的两个方法构成了方法的重载 void talk(){ System.out.println("我是"+name+"今年:"+age); } void talk(int age){ System.out.println(age); } int mOl(int num){ return num*num; } int mOl(int num, int number){ return num*number; } String mOl(String str){ return "这个是:"+str; } int max(int num, int number){ int max = (num > number)? num :number; return max; } double max(double num, double number){ double max =(num > number)? num :number; return max; } }
可变形参:
可变行参的格式: 数据类型....变量名
oublic vold nick(String .... name){ // 可以给nick这个方法传递无限多个的字符串类型的参数 }
当调用可变个数行参的方法时,传入的参数可以是0个1个或者多个
变量的赋值:
如果变量是基本数据类型,此时赋值的变量是变量所保存的数据值 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值
如果参数是基本数据类型,此时实参赋值给形参的是实参的真实的数据值
参数的赋予的时候地址的转换:
两个参数的值的赋予:普通数据类型在赋值的时候是只有一个栈空间的。把值在copy一份给另一个参数的。引用数据类型的值的赋予时候是堆空间都指向同一个 只有栈空间的名字不同,所以当一个改变的时候会带动堆空间的值的改变那就是都改变了
引用数据类型赋值
基础数据和引用数据在值的交换的注意
public class swap { public static void main(String[] args) { swap sw = new swap(); // 创造公共类对象 swp s = new swp(); s.m =19; s.n=6; s.swap(s.m,s.n); System.out.println("m: "+s.m+"n:"+s.n); // m :19 , n:6 大家思考下为什么没有换成呢? 因为 你这个m的值和下面的方法中的值是两个了 因为此时的m和n是基础数据类型在栈中有不同的位置 方法中换了
但是最初定义的没有换
sw.swap(s); // 因为方法定义在公共类中只能通过公共类来调用 System.out.println("m: "+s.m+"n:"+s.n); //m: 6n:19 因为引用数据类型的值指向的都是一样的所以可以交换成功 } public void swap(swp s){ //使用引用数据类型来当行参 int tmp = s.m; s.m = s.n; s.n = tmp; } } class swp{ int m; int n; public void swap(int m, int n){ int tmp = m; m = n; n = tmp; } }
行参是方法定义时,声明在小括号内的参数
实参:方法调用时,实际传递给行参的数据
例题
public class AprilThreeAfternoonTestOne { public static void main(String[] args) { AprilThreeAfternoonTestOne aprilThreeAfternoonTestOne = new AprilThreeAfternoonTestOne(); aprilThreeAfternoonTestOne.first(); } public void first(){ int i = 5; AprilThreeAfternoon aprilThreeAfternoon = new AprilThreeAfternoon(); aprilThreeAfternoon.i = 25; second(aprilThreeAfternoon,i); System.out.println(aprilThreeAfternoon.i); } public void second(AprilThreeAfternoon aprilThreeAfternoon, int i){ i = 0; aprilThreeAfternoon.i = 20; AprilThreeAfternoon af = new AprilThreeAfternoon(); aprilThreeAfternoon = af; System.out.println(aprilThreeAfternoon.i +" "+ i ); } } class AprilThreeAfternoon{ int i = 15; }
15 0 20 20 是因为在second结束之后就释放了所覆盖的所以又回到了以前所赋值的
面试题:
定义一个int型的数组:int[] arr = new int[]{12,3,3,34,56,77,432}; 让数组的每个位置上的值去除以首位置的元素,得到的结果,作为该位置上的 新值。遍历新的数组
答案:
//错误写法 for(int i= 0;i < arr.length;i++){ 因为这样就会把除去的数字当作第一位数字了 arr[i] = arr[i] / arr[0]; } //正确写法1 for(int i = arr.length – 1;i >= 0;i--){ arr[i] = arr[i] / arr[0]; } //正确写法2 int temp = arr[0]; for(int i= 0;i < arr.length;i++){ arr[i] = arr[i] / temp; }
计算1-100直接所有自然数的和:
public static void main(String[] args) { jia ji = new jia(); System.out.println(ji.sum(100)); } public int sum(int num){ if(num == 1){ return 1; }else { return num+sum(num-1); } } }