4、面向对象(上)(3天) | |
4.1 面向对象与面向过程 | 0.5课时 |
4.2 java语言的基本元素:类和对象 | 0.5课时 |
4.3 类的成员之一:属 性 | 0.5课时 |
4.4 类的成员之二:方 法 | 0.5课时 |
4.5 对象的创建和使用 | 1课时 |
4.6 再谈方法 | 1课时 |
4.6 再谈方法 | 1课时 |
4.7 面向对象特征之一:封装和隐藏 | 1课时 |
4.8 类的成员之三:构造器(构造方法) | 1课时 |
4.9 关键字:this的使用 | 1课时 |
4.10 关键字:package、import的使用 | 1课时 |
4-1 面向对象与面向过程
何谓“面向对象”的编程思想?
1.我要开车去丽江,这句话包含的类和方法有什么?
2.体会以下几个经典案例涉及到的类和方法。
- 人在黑板上画圆
- 列车司机紧急刹车
- 售货员统计收获小票的金额
- 你把门关上了
4-2 java语言的基本元素:类和对象
* 面向对象中的两个核心概念:类 与 对象
* 类:一类事物的描述,抽象的、概念上的定义。
* 对象:类的具体的体现,实实在在存在的个体。
*
* Scanner类
* Scanner s = new Scanner(System.in); s:对象 s.next();
*
* 面向对象程序设计的重点是类的设计
/**
* @author Heaton
* @email tzy70416450@163.com
* @date 2018/9/13 0013 11:06
* @describe 面向对象思想的体现一: 类和对象的创建
* 1.创建类,即为提供类的内部结构,属性和方法
* 2.创建类的对象(类的实例化,实例化类)new
* 3.可以通过‘对象’.属性 或者 ‘对象’.方法() 调用相关功能
*/
public class PersonTest {
public static void main(String[] args) {
//2。创建类的对象(类的实例化,实例化类)new
Person p = new Person();
//3.可以通过‘对象’.属性 或者 ‘对象’.方法() 调用相关功能
System.out.println(p.name);
System.out.println(p.age);
p.isMale = true;
System.out.println(p.isMale);
p.name = "小王";
System.out.println(p.name);
//Person@28d93b30
System.out.println(p);
p.eat();
p.dispaly();
p.speak();
p.showNation("中国");
System.out.println("***************");
//p和p1是一个对象么? 不是 new关键字堆里新开空间
Person p1 = new Person();
//断指针
//p1=null;NullPointerException
p1.name = "Tom";
System.out.println(p1.isMale);
//不同对象属性和方法是不共享的。
p.dispaly();
p1.dispaly();
Person p2 = p1;//同一对象,将p1引用地址复制给p2,此时p1和p2指向堆空间中的同一个对象实体
p1.name = "jerry";
System.out.println(p2.name);
}
}
/**
* @author Heaton
* @email tzy70416450@163.com
* @date 2018/9/13 0013 11:11
* @describe 放在和测试类同级的位置
* 1。创建类,即为提供类的内部结构,属性和方法
* 人类
*/
class Person{
//1.1属性
//姓名
String name;
//年龄
int age = 1;
//是不男
boolean isMale;
//1.2方法
public void speak(){
System.out.println("人能说话");
}
public void eat(){
System.out.println("人能吃饭");
}
public void showNation(String nation){
System.out.println("我的国籍是:"+nation);
}
public void dispaly(){
if(isMale){
System.out.println("男子汉");
}else{
System.out.println("萌妹子");
}
}
}
4-3 类的成员一:属性
4-4 类的成员二:方法
4-5 对象的创建和使用
案例
/**
* 类中属性的使用
* 成员变量(或属性) vs 局部变量
* 1.相同点:① 声明的格式是相同的:数据类型 变量名 = 初始化值
* ② 先声明,后使用
* ③ 变量都有作用域。
*
* 2.不同点:①类中声明的位置的不同。
* 成员变量:在类的一对{}内直接声明的变量
* 局部变量:方法内声明的,方法的形参位置声明的,构造器内声明的,代码块内声明的都是局部变量。
*
* ②成员变量可以在数据类型前声明权限修饰符,而局部变量是不可以声明权限修饰符的。
* 补充:权限修饰符有哪些?public 、 private 、 protected、缺省
*
* ③成员变量:声明时,有默认初始化值。也就是说,我们在定义成员变量时,可以不显式的赋值。
* 整型:byte、short 、 int 、 long :0
* 浮点型:float 、 double : 0.0
* 字符型:char:0 (或表示为'u0000')
* 布尔型:boolean : false
*
* 引用数据类型:null
* 局部变量:没有默认初始化值。必须在调用前,显式的赋值
* 特别的:方法的形参。此局部变量在方法内调用前,不需要赋值。它的赋值,是在方法调用时进行的。
*
* ④ 二者在内存中存放的位置,是不同的。
* 成员变量:存放在堆空间中
* 局部变量:存放在栈空间中
*
*
* 回忆:变量的分类:按照数据类型分类:基本数据类型(8个) vs 引用数据类型(3个:数组、类、接口)
* 按照变量在类中声明的位置的不同:成员变量(或属性) vs 局部变量
*
*
*/
public class User {
//属性
String name = null;
private int age;
public void show(String nation){//nation:局部变量
String color;//color:局部变量
color = "yellow";
System.out.println("我的国籍是:" + nation + ",肤色是:" + color);
System.out.println("name = " + name);
}
public void show1(){
System.out.println("name = " + name);
// System.out.println("肤色是:" + color);
}
}
public class UserTest {
public static void main(String[] args) {
User u1 = new User();
u1.show("USA");
}
}
案例
public class StudentTest {// 测试类
public static void main(String[] args) {
Student s = new Student();
s.name = "李鸿";
s.age = 20;
s.major = "计算机专业";
s.interests = "漫画";
System.out.println(s.name);
s.say();//方法内调用了s对象的属性
}
}
// 学生类
class Student {
// 属性
String name;
int age;
String major;
String interests;
// 方法
public void say() {
System.out.println("name : " + name + ",age : " + age +
", major : " + major + ",interests : " + interests);
}
}
拓展案例
/*
* 匿名对象的使用
*
* 1.匿名对象:创建了类的对象,但是并没有声明给一个对象引用。
* 2.特点:匿名对象只能被调用一次。
* 3.应用:常常在调用方法时,将一个匿名对象作为参数传递过去。
*/
public class PhoneTest {
public static void main(String[] args) {
Phone p1 = new Phone();//p1:对象的引用
p1.price = 699;
p1.sendEmail();
//匿名对象的创建和使用
new Phone().sendEmail();//匿名对象1
new Phone().call();//匿名对象2
//*****应用场景*********
PhoneFactory factory = new PhoneFactory();
factory.display(new Phone());
}
}
class PhoneFactory{
public void display(Phone phone){
phone.call();
phone.sendEmail();
}
}
class Phone{
double price;//价格
public void sendEmail(){
System.out.println("手机可以收发邮件!");
}
public void call(){
System.out.println("可以视频通话!");
}
}
/** * 小结一下 * 类中方法的使用 * 0.方法:类中声明的一个结构,能够实现具体功能。 比如:Arrays.sort(int[] arr) /int Arrays.binarySearch(int[] arr,int value) * * 1.举例: * public void eat(String food){} * public void show(){} * public int returnAge(){} * public String info(String nation,String color){} * * 2. 方法声明的格式: * 权限修饰符 返回值类型 方法名(形参列表){ * 方法体 * } * * 3.具体说明: * 1)权限修饰符:可以理解为所被修饰的结构能被调用的范围的大小。 * 有如下的权限修饰符:public protected 缺省 private. * 目前,大家如果声明方法,可以先都是用public * 2)关于返回值类型:没有返回值:void * 有返回值:指明具体的返回值的类型。 * 如果方法声明时,有返回值,那么我们就需要在方法体执行中,返回具体的满足相应类型的变量或常量。 * 比如:return 1 或 return index; * 说明:如果方法有返回值,方法体中一定有return! * 3)方法名,属于标识符。需要命名时,满足标识符的命名规则和规范,"见名知意". * println() / sort() / binarySearch() / random() / sqrt() / equals() * * 4)形参列表:可以声明0个,1个或多个变量。如果声明了多个变量,中间用","隔开 * 5)方法体:我们调用方法时,要执行的逻辑。 * 方法的功能,主要体现在方法体上。 * * 4. 1)方法中调用当前类的属性或方法。 (如果方法A中调用方法A:递归方法) * 2)在方法体中,可以使用关键字:return。 return的意思:返回、跳出。 * return 语句后面,不能有执行语句的。 * 3)在方法内,不能再定义方法,可以调用方法。 */ public class CustomerTest { public static void main(String[] args) { Customer c = new Customer(); String info = c.info("CHN", "yellow"); System.out.println(info);
c.eat("梨");
}
}
class Customer{
//属性
String name;
int age;
//方法
public void eat(String food){
System.out.println("我想吃:" + food);
// eat("苹果");
}
public String info(String nation,String color){
// System.out.println("我的国籍是:" + nation + ",我的肤色是:" + color);
// return 123;//错误的
eat("榴莲");
return "我的国籍是:" + nation + ",我的肤色是:" + color;
}
public void show(){
System.out.println("name : " + name + ", age : " + age);
// return 1;//错误的
return ;//在void声明的方法中,也可以提供return.
//System.out.println("我要结束单身生活!");
}
public void method(){
if(5 > 3){
return ;
//....
}
System.out.println("hello!");
//方法体内不能定义方法
// public void method1(){
//
// }
}
}
4-6 再谈方法
- 4.6.1 方法的调用
- 4.6.2 方法的重载
- 4.6.3 可变形参的方法
- 4.6.4 方法的参数传递
- 4.6.5 递归方法
案例
/*
* 课后练习2-1
* 要求:(1)创建Person类的对象,设置该对象的name、age和sex属性,调用study方法,
* 输出字符串“studying”,调用showAge()方法显示age值,调用addAge()方法给对象的age属性值增加2岁。
(2)创建第二个对象,执行上述操作,体会同一个类的不同对象之间的关系。
*
*
*/
public class PersonTest {//测试类
public static void main(String[] args) {
Person p = new Person();// int i = 10; String s = "AA"; Person:类--->引用数据类型--->变量
p.name = "韩梅梅";
p.age = 30;
p.sex = 0;
p.study();
p.showAge();
int newAge = p.addAge(2);
System.out.println(newAge);
p.showAge();
//创建新的对象
Person p1 = new Person();
p1.showAge();
}
}
class Person{
String name;
int age;
int sex;//性别 : 0:女 1: 男
public void study(){
System.out.println("studying");
}
public void showAge(){
//调用属性
System.out.println("age : " + age);
}
public int addAge(int i){
age += i;
return age;//将新的age值返回
}
}
/* * 练习2 - 2 :利用面向对象的编程方法,设计类Circle计算圆的面积。 */ public class CircleTest {//测试类 public static void main(String[] args) { Circle c1 = new Circle();
System.out.println(c1.radius);//0.0
c1.radius = 2.0;
c1.findArea();
// c1.findArea(2.0);
double area = c1.findArea1();
System.out.println(area);
}
}
class Circle{
//属性
double radius;//半径
//方法1:用于计算圆的面积
public void findArea(){
double area = Math.PI * radius * radius;
System.out.println("area : " + area);
}
//方法2:
public double findArea1(){
double area = Math.PI * radius * radius;
return area;
}
//错误的:
public void findArea(double r){
double area = Math.PI * r * r;
System.out.println("area : " + area);
}
}
案例
/*
* 练习2 - 3:
* 3.1 编写程序,声明一个method方法,在方法中打印一个10*8 的矩形,在main方法中调用该方法。
*
* 3.2 修改上一个程序,在method方法中,除打印一个10*8的矩形外,再计算该矩形的面积,并将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
*
*
* 3.3 修改上一个程序,在method方法提供m和n两个参数,方法中打印一个m*n的矩形,并计算该矩形的面积, 将其作为方法返回值。在main方法中调用该方法,接收返回的面积值并打印。
*/
public class MethodTest {
public static void main(String[] args) {
// 在static的方法中,调用非static的方法,需要使用对象进行调用。
MethodTest m = new MethodTest();
int area = m.method();
System.out.println("该矩形的面积为:" + area);
System.out.println();
int area1 = m.method(12, 5);
System.out.println("面积为:" + area1);
}
// 3.1
// public void method() {
//
// for (int i = 0; i < 10; i++) {
// for (int j = 0; j < 8; j++) {
// System.out.print("*");
// }
// System.out.println();
// }
//
// }
// 3.2
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.3
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 m * n;
}
public void method1() {
method();
}
}
案例
/*
* 定义类Student,包含三个属性:学号number(int),年级state(int),成绩score(int)。
* 创建20个学生对象,学号为1到20,年级和成绩都由随机数确定,打印出3年级(state值为3)的学生信息。
提示:
1) 生成随机数:Math.random(),返回值类型double;
2) 四舍五入取整:Math.round(double d),返回值类型long。
*/
public class Student {
int number;//学号
int state;//年级
int score;//成绩
public void info(){
System.out.println("number : " + number + ",state : " + state + ",score : " + score);
}
}
/* * 关于对象数组的使用。 * * * */ public class StudentTest { public static void main(String[] args) {
//回顾
// String[] arr = new String[10];//int i = 10;
// arr[0] = "AA";//String s = "AA";
// arr[1] = new String("BB");
//创建20个学生对象构成的数组
Student[] students = new Student[20];
for(int i = 0;i < students.length;i++){
students[i] = new Student();
//给每一个学生的属性赋值
students[i].number = i + 1;//给每一个学生对象的学号赋值
students[i].state = (int)(Math.random() * 6) + 1;//给每一个学生对象年级赋值
students[i].score = (int) Math.round(Math.random() * 100);//给每一个学生对象成绩赋值
}
//通过遍历的方式,获取state == 3的学生信息
for(int i = 0;i < students.length;i++){
if(students[i].state == 3){
Student s = students[i];
//方式一:
// System.out.println("number :" + s.number + ",state : " + s.state + ",score : " + s.score);
//方式二:
s.info();
}
}
}
}
拓展案例
/*
* 匿名对象的使用
*
* 1.匿名对象:创建了类的对象,但是并没有声明给一个对象引用。
* 2.特点:匿名对象只能被调用一次。
* 3.应用:常常在调用方法时,将一个匿名对象作为参数传递过去。
*/
public class PhoneTest {
public static void main(String[] args) {
Phone p1 = new Phone();//p1:对象的引用
p1.price = 699;
p1.sendEmail();
//匿名对象的创建和使用
new Phone().sendEmail();//匿名对象1
new Phone().call();//匿名对象2
//*****应用场景*********
PhoneFactory factory = new PhoneFactory();
factory.display(new Phone());
}
}
class PhoneFactory{
public void display(Phone phone){
phone.call();
phone.sendEmail();
}
}
class Phone{
double price;//价格
public void sendEmail(){
System.out.println("手机可以收发邮件!");
}
public void call(){
System.out.println("可以视频通话!");
}
}
数组的操作工具封装 拓展案例
public class ArrayUtil {
// 求数组的最大值
public int getMax(int[] arr) {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
return max;
}
// 求数组的最小值
public int getMin(int[] arr) {
int min = arr[0];// alt + shift + r
for (int i = 1; i < arr.length; i++) {
if (min > arr[i]) {
min = arr[i];
}
}
return min;
}
// 求数组的总和
public int getSum(int[] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
return sum;
}
// 求数组的平均数
public int getAvg(int[] arr) {
int avg;
avg = getSum(arr) / arr.length;
return avg;
}
// 数组的复制
public int[] copy(int[] arr) {
int[] arr1 = new int[arr.length];
for (int i = 0; i < arr1.length; i++) {
arr1[i] = arr[i];
}
return arr1;
}
// 数组的反转
public void reverse(int[] arr) {
for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// 数组中指定元素的查找:线性查找
// 如果在数组中找到了此元素,则返回元素在数组中的索引。如果没找到,返回-1.
public int getIndex(int[] arr, int value) {
for (int i = 0; i < arr.length; i++) {
if (value == arr[i]) {
return i;
}
}
return -1;
}
// 数组的排序:使用冒泡排序实现
public void sort(int[] arr,String detail) {
if("ascend".equals(detail)){//if(detail.equals("ascend")){//升序:从小到大
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {// 比较相邻的两个元素的值所需要的索引
if (arr[j] > arr[j + 1]) {
// int temp = arr[j];
// arr[j] = arr[j + 1];
// arr[j + 1] = temp;
//正确的交换
swap(arr,j,j + 1);
//不正确的交换
// swap(arr[j],arr[j + 1]);
}
}
}
}else if("descend".equals(detail)){//}else if(detail.equals("descend")){//降序:从大到小
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {// 比较相邻的两个元素的值所需要的索引
if (arr[j] < arr[j + 1]) {
// int temp = arr[j];
// arr[j] = arr[j + 1];
// arr[j + 1] = temp;
//正确的交换
swap(arr,j,j + 1);
//不正确的交换
// swap(arr[j],arr[j + 1]);
}
}
}
}else{
System.out.println("输入的排序方式有误!");
}
}
//
public void swap(int[] arr,int i,int j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public void swap(int m,int n){
int temp = m;
m = n;
n = temp;
}
//遍历数组
public void print(int[] arr){
for(int i = 0;i < arr.length;i++){
System.out.print(arr[i] + " ");
}
System.out.println();
}
}
public class ArrayUtilTest { public static void main(String[] args) { ArrayUtil util = new ArrayUtil();
int[] arr1 = new int[]{23,5,23,64,66,-9,75,-77,3};
int max = util.getMax(arr1);
System.out.println("最大值为:" + max);
int avg = util.getAvg(arr1);
System.out.println("平均数为:" + avg);
int[] arr2 = util.copy(arr1);//arr2是对arr1的复制
util.reverse(arr1);
System.out.println("遍历arr1:");
util.print(arr1);
System.out.println("遍历arr2:");
util.print(arr2);
System.out.println("对arr1进行排序");
util.sort(arr1,"ascend");
util.print(arr1);
System.out.println("查找66在arr2数组中出现的位置");
int index = util.getIndex(arr2, 666);
if(index != -1){
System.out.println("找到了指定元素,在数组中的索引为:" + index);
}else{
System.out.println("在数组中未找到指定的元素");
}
}
}
no yes yes yes yes no no
可变形参案例
/**
* 可以个数形参的方法的使用:jdk5.0新特性
* 1.可变个数形参的格式:数据类型 ... 变量名
* 2.可变个数形参的方法在调用时,给可变个数的形参赋值时,可以赋值的个数为:0个,1个,。。。。
* 3.可变个数形参的方法与同名的方法之间,彼此构成重载
* 4.可变个数形参的方法与形参类型相同的数组的方法不能同时出现在类中。
* 5.可变个数形参必须声明为方法形参的最后一个参数。
* 6.在一个方法的形参位置,最多只能声明一个可变个数形参
*
*/
public class MethodArgsTest {
public static void main(String[] args) {
MethodArgsTest m = new MethodArgsTest();
m.show(1);
m.show();
m.show("AA");
m.show("AA","BB");
m.show(new String[]{"AA","BB"});
}
public void show(int i) {
System.out.println(i);
}
// public void show(String s) {
// System.out.println(s);
// }
// 可变个数形参的方法
public void show(String ... strs) {
System.out.println("哈哈!");
for(int i = 0;i < strs.length;i++){
System.out.println(strs[i]);
}
}
//不能再声明了。
// public void show(String[] strs){
//
// }
public void show(int i,String... strs) {
}
//The variable argument type String of the method show must be the last parameter
// public void show(int... strs,int i) {
//
// }
}
案例
/**
* 变量的值传递机制:
* 如果赋值的基本数据类型的变量,则传递的是基本数据类型变量所保存的具体的数值。
* 如果赋值的引用数据类型的变量,则传递的是引用数据类型变量所保存的地址值。
*
*/
public class ValueTransferTest1 {
public static void main(String[] args) {
int m = 10;
int n = m;
System.out.println("m = " + m + ",n = " + n);
m = 20;
System.out.println("m = " + m + ",n = " + n);
System.out.println("------------------");
Order o1 = new Order();
o1.orderId = 1001;
Order o2 = o1;//o1,o2就同时指向堆空间中创建的同一个对象实体
System.out.println(o2.orderId);//1001
o2.orderId = 1002;
System.out.println(o1.orderId);
}
}
class Order{
int orderId;
}
/** * * 方法的参数的传递机制:值传递机制 * * 1.形参:方法在声明时,指明的参数。 * 实参:方法在被调用时,具体给形参赋的值,就是实参 * * 2.如果方法的形参是基本数据类型的变量,则方法调用时,传递的实参即为基本数据类型变量所保存的具体的数值。 * 如果方法的形参是引用数据类型的变量,则方法调用时,传递的实参即为引用数据类型变量所保存的地址值。 */ public class ValueTransferTest2 {
public static void main(String[] args) {
int m = 10;
int n = 5;
System.out.println("m = " + m + ",n = " + n);
//交换m和n的值
// int temp = m;
// m = n;
// n = temp;
//并没有实现m和n值的交换
ValueTransferTest2 v = new ValueTransferTest2();
v.swap(m, n);
System.out.println("m = " + m + ",n = " + n);
}
//交换m和n变量的值。--没有成功
public void swap(int m ,int n){
int temp = m;
m = n;
n = temp;
}
}
public class ValueTransferTest3 { public static void main(String[] args) {
Data d = new Data();
System.out.println("m = " + d.m + ",n = " + d.n);
//调用方法,实现Data中m和n值的互换
ValueTransferTest3 v = new ValueTransferTest3();
v.swap(d);
System.out.println("m = " + d.m + ",n = " + d.n);
}
public void swap(Data data){
int temp = data.m;
data.m = data.n;
data.n = temp;
}
}
class Data{
int m = 10;
int n = 5;
}
案例
法一:
public static void test(int a, int b) {
// 在不改变原本题目的前提下,如何写这个函数才能在main函数中输出a=100,b=200?
a = a*10;
b = b*20;
System.out.println(a);
System.out.println(b);
System.exit(0);
}
法二:
public static String method(int a , int b){
a = a*10;
b = b*10;
String re = new String("a:"+a + "b:"+b);
return re;
}
案例
/**
* 递归方法的使用
* 1.递归方法:一个方法体内调用它自身。
*
* 2.方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
*
* 3.递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
*
*/
public class RecursionTest {
public static void main(String[] args) {
RecursionTest t = new RecursionTest();
int value = t.mul(5);
System.out.println(value);
int value1 = t.func(10);
System.out.println(value1);
}
//练习1:请用Java写出递归求阶乘(n!)的算法
public int mul(int num){
if(num == 1){
return 1;
}else{
return num * mul(num - 1);
}
}
//练习2:已知有一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),其中n是大于0的整数,求f(10)的值。
public int func(int num){
if(num == 0){
return 1;
}else if(num == 1){
return 4;
}else{
//正确的写法
return 2 * func(num - 1) + func(num - 2);
//错误的写法
// return func(num + 2) - 2 * func(num + 1);
}
}
//练习3:已知一个数列:f(20) = 1,f(21) = 4,f(n+2) = 2*f(n+1)+f(n),其中n是大于0的整数,求f(10)的值。
}
我今天去百度面试,遇到一个一个双重递归调用的问题,我琢磨了一下,完全不知道为什么。打断点了,也还是没看懂为什么程序会那样走。您有空可以看一下,求指教
案例
private int count = 0;
public int recursion(int k){
count++;
System.out.println("count1:" + count + " k:" + k);
if(k <= 0){
return 0;
}
return recursion(k - 1) + recursion(k - 2);//287
//return recursion(k - 1);//11
//return recursion(k - 1) + recursion(k - 1);//2047
}
//递归方法的使用练习: public class RecursionTest1 {
private int count = 0;
public int recursion(int k) {
count++;
System.out.println("count1:" + count + " k:" + k);
if (k <= 0) {
return 0;
}
return recursion(k - 1) + recursion(k - 2);// 287
// return recursion(k - 1);//11
// return recursion(k - 1) + recursion(k - 1);//2047
}
public static void main(String[] args) {
RecursionTest1 r = new RecursionTest1();
r.recursion(4);
}
}
4-7 面向对象特征之一:封装与隐藏
案例
/**
* 面向对象的特征一:封装与隐藏 3w: what? why? how?
*
* 1.问题的引入?
* 我们在创建了一个类的对象以后,通过"对象.属性"的方式,可以给对象的属性赋值。对此属性的赋值,是有限制的,比如:数据类型和
* 数据类型储值范围的限制。但是,在实际问题中,还通过需要额外的限制。同时这些额外的限制,不可能在属性的声明中加上限制逻辑。
* 那么,我们只能考虑通过方法,对属性的赋值进行额外的限制。同时,我们必须禁止再直接通过"对象.属性"的方式,对属性进行赋值。
*
* 2.封装性的体现:(狭义上的体现)
* 私有化(private)类的属性xxx,同时,提供公共的(public)设置(setXxx())和获取(getXxx())的方法
*
* 3.封装性的体现:(广义上的体现)
* 3.1 java规定的4种权限修饰:(从小到大) private 缺省 protected public
* 3.2 java规定的4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类。
* 3.3 具体来讲:4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类。
* 只能使用缺省 或者 public 来修饰类
*/
public class AnimalTest {
public static void main(String[] args) {
Animal a = new Animal();
a.name = "老虎";
a.age = 2;
// a.legs = 3;//报错
a.setLegs(4);
// a.legs = 3;
a.show();
System.out.println(a.getLegs());
}
}
class Animal{//动物类
private String name;
int age;
private int legs;//腿
public void eat(){
System.out.println("动物进食");
}
public void sleep(){
System.out.println("有些动物需要冬眠");
}
public void show(){
System.out.println("name : " + name + ",age : " + age + ",legs : " + legs);
}
//通过方法的调用,对legs属性进行赋值
public void setLegs(int l){
if(l < 0 || l % 2 != 0){
System.out.println("输入的数据非法!");
}else{
legs = l;
}
}
public int getLegs(){
return legs;
}
}
权限演示案例
public class Order {
private int orderPrivate;
int orderDefault;
public int orderPublic;
private void methodPrivate(){
orderPrivate = 1;
orderDefault = 2;
orderPublic = 3;
}
void methodDefault(){
orderPrivate = 1;
orderDefault = 2;
orderPublic = 3;
}
public void methodPublic(){
orderPrivate = 1;
orderDefault = 2;
orderPublic = 3;
}
}
public class OrderTest { public static void main(String[] args) { Order o = new Order();
o.orderDefault = 1;
o.orderPublic = 2;
// o.orderPrivate = 3;//由于声明为private,不能在Order类外部进行调用
o.methodDefault();
o.methodPublic();
// o.methodPrivate();//由于声明为private,不能在Order类外部进行调用
}
}
4-8 类的成员之三:构造器(构造方法)
案例
/**
* 类的成员之三:构造器 (constructor,构造方法) construct:建造、建设 construction
*
*
* 1.构造器的作用:① 创建类的对象 ② 初始化对象的属性
*
* 2.说明:
* ①如果在定义一个类时,没有显式的声明类的构造器。那么系统会自动给类提供一个无参的构造器。
* ②如何声明一个类的构造器。格式:权限修饰符 类名(形参列表){ }
* ③如果我们在类中一旦定义类的构造器,那么系统就不再提供默认的无参的构造器了。
* ④类的多个构造器之间,彼此构成重载
* ⑤总结:类中,一定会有构造器!
*
* 3.关于类中属性赋值的先后顺序:
* ①默认初始化 - ②显式初始化 - ③构造器中初始化 - ④通过"对象.属性" 或 "对象.方法"的方法,给属性赋值
*
*
*/
public class PersonTest {
public static void main(String[] args) {
Person p1 = new Person();
p1.eat();
Person p2 = new Person("Tom",12);
System.out.println(p2.name);
System.out.println(p2.age);
//验证属性赋值的顺序
Person p3 = new Person();
System.out.println(p3.name);
Person p4 = new Person("BB");
System.out.println(p4.name);
p4.name = "CC";
System.out.println(p4.name);
}
}
class Person{
//属性
String name = "AA";
int age;
//构造器
public Person(String n){
System.out.println("hello!");
name = n;
}
public Person(int a){
age = a;
}
public Person(String n,int a){
name = n;
age = a;
}
//不能再声明了
// public Person(String m){
//
// }
public Person(){
}
//方法
public void eat(){
System.out.println("吃饭");
}
public void sleep(int hour){
System.out.println("睡觉,睡了" + hour + "个小时");
}
}
案例
public class Person {
private int age;
private String name;
public Person(){
age = 18;
}
public Person(String n,int a){
name = n;
age = a;
}
public void setAge(int a){
if(a < 130 && a >= 0){
age = a;
return;
}
System.out.println("输入的数据非法!");
}
public int getAge(){
return age;
}
public void setName(String n){
name = n;
}
public String getName(){
return name;
}
}
案例
/*
3题
*/
class Point {
double xCoord;
double yCoord;
double zCoord;
public Point(double x,double y,double z) {
xCoord = x;
yCoord = y;
zCoord = z;
}
public void setXcoord(double x) {
xCoord = x;
}
public void setYcoord(double y) {
yCoord = y;
}
public void setZcoord(double z) {
zCoord = z;
}
public double getXcoord() { //获得一个横坐标 注意 有返回值 定义方法的类型就不能用void 否则要报错“意外的返回值”
return xCoord;
}
public double getYcoord() { //获得一个纵坐标
return yCoord;
}
public double getZcoord() {//获得z坐标
return zCoord;
}
public void display() {//输出方法
System.out.println("(" + xCoord + "," + yCoord + "," + zCoord + ")");
}
public double coordSquare() { //各点到原点的平方
double sum = 0.0;
sum = xCoord * xCoord + yCoord * yCoord + zCoord * zCoord;
return sum;
}
}
public class TestPoint {
public static void main(String[] args) {
TestPoint test = new TestPoint();
Point point1 = new Point(-4,2,3);
Point point2 = new Point(-1.2,-3.56,8.23);
System.out.println("没改动之前,直接输出情况:");
point1.display();
point2.display();
System.out.println("没改动前,point1的平方和:" + point1.coordSquare());
System.out.println("没改动前,point2的平方和:" + point2.coordSquare());
test.changeX(point2);
test.changeY(point2);
test.changeZ(point2);
System.out.println("改动后,直接输出情况:");
point1.display();
point2.display();
System.out.println("没改动前,point2的平方和:" + point2.coordSquare());
}
public void changeX(Point x) {//改变坐标值x方法
x.setXcoord(0);
}
public void changeY(Point y) {//改变坐标值y方法
y.setYcoord(0);
}
public void changeZ(Point z) {//改变坐标值z方法
z.setZcoord(0);
}
}
/*4题 * 考查:封装性、构造器的使用 * 编写两个类,TriAngle和TriAngleTest,其中TriAngle中声明私有的底边长base和高height, * 同时声明公共方法访问私有变量。此外,提供类必要的构造器。另一个类中使用这些公共方法,计算三角形的面积。
*/
public class TriAngleTest {
public static void main(String[] args) {
TriAngle t = new TriAngle(12.3, 2.3);
double area = t.findArea();
System.out.println("三角形的面积为:" + area);
t.setBase(2.3);
t.setHeight(2.4);
area = t.findArea();
System.out.println("三角形的面积为:" + area);
}
}
class TriAngle{
private double base;//底边长
private double height;//高
public TriAngle(){
}
public TriAngle(double b,double h){
base = b;
height = h;
}
public void setBase(double b){
base = b;
}
public double getBase(){
return base;
}
public void setHeight(double h){
height = h;
}
public double getHeight(){
return height;
}
//求三角形的面积
public double findArea(){
return base * height / 2;
}
}
4-9 关键字:this的使用
案例
/**
* this关键字的使用:
* 1.this:可以理解为:当前对象 或 当前正在创建的对象
*
* 2.this可以用来调用:属性、方法、构造器
*
* 3.this调用属性、方法
* 在方法中:我们可以在方法中通过"this.属性"或者"this.方法"的方法,表示调用当前对象的指定属性或方法。但是通常
* 情况下,我们都省略了"this."。但是如果方法的形参和当前对象的属性名相同的情况下,我们必须显式的使用"this.变量"的方式,
* 表明此变量是属性,而非形参。
*
* 在构造器中:我们可以在构造器中通过"this.属性"或者"this.方法"的方法,表示调用当前正在创建的对象的指定属性或方法。
* 但是通常情况下,我们都省略了"this."。但是如果构造器的形参和当前正在创建的对象的属性名相同的情况下,我们必须显式的使用"this.变量"的方式,
* 表明此变量是属性,而非形参。
*
* 4.this调用构造器:
* 1.可以在类的构造器中使用"this(形参列表)"的方式,调用本类中重载的其他的构造器!
* 2.明确:构造器中不能通过"this(形参列表)"的方式调用自身构造器
* 3.如果一个类中声明了n个构造器,则最多有 n - 1个构造器中使用了"this(形参列表)"
* 4."this(形参列表)"必须声明在类的构造器的首行!
* 5.在类的一个构造器中,最多只能声明一个"this(形参列表)"
*/
public class PersonTest {
public static void main(String[] args) {
Person p = new Person();
p.setName("Tom");
p.setAge(12);
System.out.println(p.getName() + ":" + p.getAge());
p.show();
System.out.println();
Person p1 = new Person("Tom");
}
}
class Person{
private String name;
private int age;
public Person(){
System.out.println("hello!");
}
public Person(String name,int age){
this(name);
//this.name = name;
this.age = age;
this.eat();
}
public Person(String name){
// this(name);
this();
this.name = name;
}
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
public void show(){
System.out.println("name : " + this.name + ",age : " + this.age);
}
public void eat(){
System.out.println("吃饭!");
this.show();
}
}
案例
public class Boy {
private String name;
private int age;
public Boy() {
}
public Boy(String name) {
this.name = name;
}
public Boy(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void marry(Girl girl){
System.out.println("我想娶" + girl.getName());
}
public void shout(){
if(this.age >= 22){
System.out.println("你可以结婚了!");
}else{
System.out.println("你还可以多谈谈恋爱!");
}
}
}
public class Girl {
private String name;
private int age;
public Girl(String name){
this.name = name;
}
public Girl(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void marry(Boy boy){
System.out.println("我想嫁给" + boy.getName());
boy.marry(this);
}
/**
* 比较两个Girl对象的大小。
* @param girl
* @return 如果返回正数,表明当前的对象大。如果返回负数,表明形参的对象大,如果返回0,表明两个对象一样大。
*/
public int compare(Girl girl){
// if(this.age > girl.age){
// return 1;
// }else if(this.age < girl.age){
// return -1;
// }else{
// return 0;
// }
// return (this.age > girl.age)? 1 : (this.age == girl.age)? 0 : -1;
return this.age - girl.age;
}
}
public class BoyGirlTest { public static void main(String[] args) {
Boy boy = new Boy("罗密欧", 24);
Girl girl = new Girl("祝英台");
boy.marry(girl);
girl.marry(boy);
girl.setAge(25);
Girl girl1 = new Girl("朱丽叶");
girl1.setAge(26);
int compare = girl.compare(girl1);
System.out.println(compare);
}
}
4-10 关键字:package、import的使用
案例
/*
* 一、package关键字的使用:
* package:包
* 1.为了方便的对项目中的类,进行统一的管理。提供了包的概念。
* 2.声明为源文件的首行
* 3.遵循标识符的命名规则和规范:xxxyyyzzz
* 4.命名时,每"."一次,代表着一层文件目录。
*
* 二、import关键字的使用:
* import:导入
* 1. 可以在源文件中使用import来导入指定包下的类或接口
* 2. 声明在类的结构和包的声明之间
* 3. 如果需要在源文件中导入多个类或接口,则并列声明出即可
* 4. 比如:import java.util.*;表示可以导入util包下的所有的类或接口
* 5. 如果使用的类或接口是java.lang下定义的,则可以省略此import语句。
* 6. 如果使用的类或接口是当前包下定义的,则可以省略此import语句。
* 7. 如果一个类中使用了不同包下的同名的类,则必须通过全类名的方法进行区分调用
* 8. import static 可以导入指定类的静态的属性、方法
* 9. 如果已经声明过导入a包下的结构(如:import java.a.*),但是如果导入a包的子包下的类或接口,仍然需要导入声明。
*/
import java.util.*;
import com.tzy.java.Order;
import com.tzy.java.PersonTest;
import com.tzy.java1.sub.JavaBean;
import java.sql.Date;
import static java.lang.Math.random;
import static java.lang.System.out;
import java.lang.reflect.Field;
public class PackageImportTest {
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
ArrayList list = new ArrayList();
HashMap map = null;
System.out.println("hello!");
String s1 = "abc";
PersonTest p = new PersonTest();
Order o = new Order();
Date date = new Date(234324L);
java.util.Date d = new java.util.Date();//全类名的方法调用
double random = random();
out.println("hello!");
Field field = null;
JavaBean b = new JavaBean();
}
}