- print(); 输出后不换行
- println(); 输出后换行
java三高 :高可用、高性能、高并发
测试jdk是否安装成功 cmd 输入 java -version
public class Hello{ public static void main(String[] args){ System.out.print("Hello world!"); } }
4.编译javac Hello.java文件,会生成一个java文件
5.运行class文件,java class名
java两种都包含,只是时机不同
文档注释
// JavaDOC:文档注释 /** */ /** * @description helloworld * @Author 作者 */
java 是强类型语言 :要求变量的使用要严格符合规定,所有的变量都必须先定义后才能使用
一旦定义了一个变量指定了某个数据类型,如果不经过转换的话他就永远是这个类型
// 整数 int num1 = 10; // 最常用 byte num2 = 21; short num3 = 30; long num4 = 30L; // long类型要在数字后面加个L // 小数:浮点数 float num5 = 50.1F; // float类型要在数字后面加个F double num6 = 3.1415926; // 字符 char name = '中'; // 字符串,String不是关键字,是类 // String namea = "chaoren"; // 不是基本类型 // 布尔值: boolean flag = true; boolean Flag = false;
public class Demo03 { public static void main(String[] args){ int i = 0; int i1 = 010; int i2 = 0x11; // 十六进制0x 0~9 A~F:10~15 System.out.println(i); System.out.println(i1); System.out.println(i2); System.out.println("==========="); // 浮点数拓展 浮点数不能表示精确的数值,不能用于比较和表示货币等 // 银行业务怎么表示? 用 BigDecimal 数学工具类 // float 有限 离散 舍入误差 约等于 接近但不等于 // double // 得出结论:最好完全避免使用浮点数进行比较 float f = 0.1f; // 0.1 double d = 1.0/10; // 0.1 System.out.println(f==d); // false float d1 = 23413153515f; float d2 = d1 + 1; System.out.println(d1==d2);// true // 字符拓展 System.out.println("============"); char c1 = 'a'; char c2 = '中'; System.out.println(c1); System.out.println((int)c1); // (int) 表示强制转换 System.out.println(c2); System.out.println((int)c2); // 强制转换 // 所有字符本质还是是数字 // char类型涉及到编码类型问题 里的Unicode编码可以处理各种语言文字 // 占两个字节 最多可表示65535个字符 0~65535 2^16=65535 // unicode 表:(97=a 65=A) unicode转义编码表示范围:U0000~UFFF char c3 = '\u0061'; // \u 表示转义字符 System.out.println(c3); // 转义字符 \t 水平制表符 \n 换行符 System.out.println("========"); String sa = new String(original:"helloworld"); String sb = new String(original:"helloworld"); System.out.println(sa==ab); // false String sc = "helloworld"; String sd = "helloworld"; System.out.println(sc==sd); // true // 对象 从内存分析 } }
不同类型混合运算不论是是赋值还是运算都是向定义时的最高位类型转
// 类型转换 public class Demo05 { public static void main(String[] args){ int i = 128; byte b = (byte)i; // 内存溢出 byte类型数值范围:-128~127 输出垃圾值 // 强制转换 (类型)变量名 高---低 int j = 128; double c = j; // 自动转换 低---高 System.out.println(i); System.out.println(b); System.out.println(j); System.out.println(c); /* 注意点: 1.不能对布尔值进行转换 2.不能把对象类型转换为不相干的类型 3.在把高容量转换到低容量的时候 用强制转换 4.转换的时候可能存在内存溢出或精度问题! */ System.out.println("========"); System.out.println((int)23.7); // double类型 23 System.out.println((int)-45.89f); // float类型 -45 System.out.println("========"); char e = 'a'; int f = e+1; System.out.println(f); System.out.println((char)f); System.out.println("========="); // 操作比较大的数时 注意溢出问题 // jdk7新特性,数字之间可以用下划线分割 int money = 10_0000_0000; // System.out.println(money); // 1000000000 int years = 20; int total = money*years; // 负数,计算时溢出了 long total2 = money*years; // 赋值前默认是int,转换之前已经存在问题了 long total3 = money*((long)years);// 先把一个数转换为long System.out.println(total3); } }
public class Demo08 { // 这是类 // 类变量前加 static // 他是从属于Demo08这个类 而且会随着该类一起出来一起消失 static double salary = 2500; // 都先把类变量加个static好去调用 // 属性:变量 // 实例变量:从属于对象(类), 作用域在类里面 不在方法里面 如果不自行初始化 这个类型的默认值 所有数值类型一般都是:0,浮点型:0.0 (char)字符串变量默认值是0 或'\u0000' 而非 '0',布尔值默认值是false 除了基本类型,其余的默认值都是null String name; // 定义的变量直接可以用 但用起来不简单 int age; // 类里面会有个默认方法 main方法 public static void main(String[] args){ // 局部变量:必须声明和初始化值 int i = 10; System.out.println(i); // 变量类型 除了基本类型 类型也可以是自己(自定义类型)也是引用类型 这个变量名字他有个值叫做new了一个Demo08 相当于把自己(变量)给拿到了 // 通过这个demo08就可以用他的东西了 Demo08 demo08 = new Demo08(); // 相当于把Demo08这个类拿到了 他会通过这个类返回一个Demo08 System.out.println(demo08.age); System.out.println(demo08.name); // 类变量 System.out.println(salary); } // 其他方法 public void add(){ } }
public class Demo09 { // 常量通过final这关键词来定义 常量名一般用大写表示 // static final 这俩是修饰符 不存在先后顺序 static final double PI = 3.14; public static void main(String[] args) { System.out.println(PI); } }
/ 号是取余数(模) %号是取商数
public static void main(String[] args) { int a = 3; int b = a++; // a++ 先给b赋值 再自增 // a = a + 1; System.out.println(a); // a = a + 1; int c = ++a; // ++a 先自增 再给c赋值 System.out.println(a); System.out.println(b); System.out.println(c); // 幂运算 使用工具类来操作 double pow = Math.pow(2,3); // 2^3 System.out.println(pow); System.out.println("================"); int i = 1; int j; System.out.println(i); // 1 j = i++; System.out.println(i); // 2 j = i++; System.out.println(i); // 3 j = i++; System.out.println(i); // 4 j = i++; System.out.println(i); // 5 j = i++; System.out.println("i=" + i); // 6 System.out.println(j); // 5 /*System.out.println("================="); i = i++; i = i++; i = i++; i = i++; i = i++; i = i++; // 进操作数栈的始终是 1 ,++是在局部变量表里完成的,赋值操作会覆盖++后的结果。 System.out.println("i=" + i); // i=1*/ /* System.out.println("=================="); int d = 2; int e = 3; int f = d++; // d=3 int g = ++e; // e=4 System.out.println(f); System.out.println(g); System.out.println(d++ + ++e);*/ } }
public static void main(String[] args) { // 与(&&) 或(||) 非(!) boolean a = true; boolean b = false; // 短路运算 int c = 5; boolean d = (c<4)&&(c++<4); System.out.println(d); System.out.println(c); }
public static void main(String[] args) { /* A = 0011 1100 B = 0000 1101 // 位运算 跟底层二进制有关 效率极高!!! A&B = 0000 1100 A与B 相与 两对应位都是1 结果为1,否则为0 A|B = 0011 1101 A或B 如果两个A、B对应位都是0 结果为0,否则为1 A^B = 0011 0001 取反(异或) 如果对应位相同为0,否则为1 ~B = 1111 0010 2*8怎么运算最快 计算机不知道2*8=16 可拆分成2*2*2*2 乘2每次在变大 在位运算里变得非常快 << 左移 *2 >> 右移 /2 >>> 右移 0000 0000 0 0000 0001 1 0000 0010 2 0000 0100 4 0000 1000 8 0001 0000 16 */ }
- 在加号两侧,只要由一方有String(字符串)类型(只要不是放最末尾) 他就会把其他的操作数都转换为String再进行连接
- 但是会有运算顺序问题
public static void main(String[] args) { int a = 10; int b = 20; // 字符运算符 在加号两侧,只要由一方有String(字符串)类型(只要不是放最末尾) 他就会把其他的操作数都转换为String再进行连接 // 但是会有运算顺序问题 System.out.println(a + b); // 30 System.out.println("" + a + b); // 1020 直接拼接 System.out.println(a + b + ""); // 30 先相加再拼接 }
public static void main(String[] args) { // 三元运算符 // x ? y : z // 如果x==true 结果为y 否则为z int score = 50; String type = score < 60 ? "不及格" : "及格"; System.out.println(type); }
- package pkg1[. pkg2[. pkg3…]];
- package com.dj.operator;
- import package1[.package2…].(className | *);
- import com.dj.base.Demo2;
- import com.dj.base.*; // 导入这个包下所有的类
调用nextInt(), next(), nextLine()等方法是用来做接收作用的,括号里可以填数字,表示要接受数字范围,
Scanner scanner = new Scanner(System.in);
public static void main(String[] args) { // 创建一个扫描器对象,用于接收键盘数据 // 创建Scanner对象,通过System.in接收用户的输入并且把它封装成scanner对象 之后用scanner进行用户的扫描测试 Scanner scanner = new Scanner(System.in); // Scanner实体化 System.out.println("使用next方式接收:"); // 判断用户有没有输入字符串 if (scanner.hasNext()) { // scanner对象是否还有下一个输入数据 String str = scanner.next(); // 创建一个str对象,调用scanner.next()方法 获取指定类型变量 停下来等待接收用户的输入 输入后自动接收 赋值给str变量 程序会等待用户输入完毕 System.out.println("输出的内容为:" + str); // 凡是属于IO流的类如果不关闭会一直占用资源,用完就关养成好习惯 scanner.close(); } }
1.Random类的作用:用来生成随机数
2.Random类的使用步骤:1.导包 2.创建Random类的对象 3.获取随机数 变量类型 变量 = 对象.nextInt() 获取
3.死循环(while 和 for)的应用
public static void main(String[] args) { // 1.1.创建Random类的对象 Random r = new Random(); // 获取(接收)指定范围的随机数(1~100) int num = r.nextInt(100) + 1; // nextInt(100)--> 0~99 加一是整个范围[0+1,99+1] System.out.println("输入你要猜的数(1~100):"); // 创建用户从键盘输入Scanner类的对象 Scanner sc = new Scanner(System.in); // 因为不知道多少次能猜对,所以用死循环改进 // 死循环写法一 while (true){ // 不确定几次猜中,用死循环一直持续下去直到猜中break出 // 接收用户输入的数据 int guessNum = sc.nextInt(); // 比较两数是否相等,给出提示 if (guessNum < num){ System.out.println("猜小了"); }else if (guessNum > num){ System.out.println("猜大了"); }else{ System.out.println("恭喜猜中"); break; // 结束循环 } } // 死循环写法二 /*for (; ; ) { // 存取猜数的对象 int guessNum = sc.nextInt(); if (guessNum < num) { System.out.println("猜小了"); } else if (guessNum > num) { System.out.println("猜大了"); } else { System.out.println("恭喜猜中"); break; // 结束循环 } }*/ }
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.println("输入内容:"); String s = scanner.nextLine(); // equals 判断字符串是否一致 if(s.equals("Hello")){ System.out.println(s); } System.out.println("end"); scanner.close(); }
public static void main(String[] args){ Scanner scanner = new Scanner(System.in); System.out.println("输入成绩"); double score = scanner.nextDouble(); if(score == 100){ System.out.println("满分"); }else if (score < 100 && score >= 60){ System.out.println("及格"); }else if(score < 60 && score >= 0){ System.out.println("不及格"); }else{ System.out.println("成绩就不合法"); } scanner.close(); }
jdk7的新特性:表达式的结果可以是字符串!
字符的本质还是数字
反编译 java文件 编译之后 -> 变成class文件(字节码文件) 用反编译工具(IDEA)反编译成java程序或一些东西
char grade = 'C'; // 单个字符 switch (grade){ case 'A': System.out.println("优秀"); break;// 可选 String name = "刘宇"; // jdk7的新特性:表达式的结果可以是字符串! // 字符的本质还是数字 // 反编译 java文件 编译之后 -> 变成class文件(字节码文件) 用反编译工具(IDEA)反编译成java程序或一些东西 switch (name){ case "大刘宇": System.out.println("大刘宇"); break; default: System.out.println("刘宇");
- while 先判断后执行
- do…while 先执行后判断; 至少执行一次
int a = 0; while (a < 0){ System.out.println(a); } System.out.println("==========="); do { System.out.println(a); }while (a < 0); while (true){ // 死循环 }
for ( ; ; ){ // 死循环 } 打印九九乘法表 // 1.先打出第一列 for (int i = 1; i <= 9; i++){ System.out.print(1 + "*" + i + "=" + (1 * i) + "\t"); } // 2.再用一个循环包起来 // 3.去掉重复项,i == j // 4.调整样式 for (int j = 1; j <= 9; j++) { for (int i = 1; i <= j; i++) { System.out.print(j + "*" + i + "=" + (j * i) + "\t"); } System.out.println(); }
int i = 0; while (i < 100){ i++; System.out.println(i); if (i == 30){ break; } } System.out.println("123");
int i = 0; while (i < 100){ i++; if (i % 10 == 0){ System.out.println(); continue; // 跳过本次所有循环内余下的操作,回到下一次是否执行循环判断 } System.out.print(i);
int count = 0; outer:for (int i = 101; i < 150; i++){ for (int j = 2; j < i/2; j++){ if (i % j == 0){ continue outer; } } System.out.print(i + " "); }
// 打印三角形 5行 for (int i = 1; i <= 5; i++){ for (int j = 5; j >= i; j--){ System.out.print(" "); } for (int j = 1; j <= i; j++){ System.out.print("*"); } for (int j = 1; j < i; j++){ System.out.print("*"); } System.out.println(); }
System.out.println(); 他是什么意思?
- System是系统的类,out 是System下的输出对象,println(); 是一个方法
- 调用**(System)系统类里面的(out)标准输出对象**中的println(); 方法。
// main方法 public static void main(String[] args){ /*int sum = add(1,2); System.out.println(sum);*/ test(); } public static void test(){ for (int i = 1; i <= 1000; i++){ if (i%5==0){ System.out.print(i + "\t"); } if (i%(5*3)==0){ System.out.println(); } } } // 加法 public static int add(int a,int b){ return a+b; }
int larger = max(30, 40);
System.out.println(“hello world”);
public static void main(String[] args){ // 静态方法 static Student.say(); // 非静态方法 // 实例化这个类 new Student() // 创建了这个类然后,再调用它的方法 // new Student().say1(); // new Student 把这个类实例化,再调用它的方法 // 对象类型 对象名 = 对象值; Student student = new Student(); // 对象值变成实例化对象 student.say1(); } // static是和类一起加载(出现)的,时间片特别早,当class Demo02存在,他就存在了 public static void a(){ // scan(); // 存在的东西调用不存在的东西就会报错 } // 跟对象有关,对象创建/类实例化(通过new)之后才存在 public void scan(){ // 非静态方法实例化后才能被调用 }
- 方法的重载(overload) loading…
- 定义,在同一个类中,允许存在一个以上的同名方法,只要他们的参数个数或者参数类型不同即可,同名不同参:”两同一不同“:同一个类、相同方法名
参数列表不同,参数个数不同,参数类型不同,参数顺序不同,主要看参数类型- 判断是否重载:跟方法的权限修饰符、返回值类型、形参变量名、方法体都无关!
- 再通过对象调用方法时,如何确定某一个指定的方法:方法名 再到—>参数列表
Demo03 test = new Demo03(); test.getSum(1,2); } // 如下4个方法构成了重载 public void getSum(int i,int j){ System.out.println("1"); // 方法体 } public void getSum(double d1,double d2){ // 参数类型不同 } public void getSum(String s,int j){ } public void getSum(int i,String s){ } /*public int getSum(int i,int j){ return 0; // 非重载 和第一个方法起冲突 第一个是输出值 这个是返回值 }*/ /*public void getSum(int m,int n){ // 与参数名无关 }*/ /*private void getSum(int i, int j){ // 与公共修饰符无关 }*/
public static void main(String[] args){ mOL(3); mOL(3,4); mOL("字符串"); int a = max(2,5); double b = max(3.4,6.5); double c = max(1.2,3.4,4.5); System.out.println(a); System.out.println(b); System.out.println(c); } public static void mOL(int i){ System.out.println("i*i=" + (i * i)); } public static void mOL(int i,int j){ System.out.println("i*j=" + (i * j)); } public static void mOL(String s){ System.out.println(s); } public static int max(int i,int j){ return i > j ? i : j; } public static double max(double i,double j){ return i > j ? i : j; } public static double max(double m,double n,double p){ double max = m > n ? m : n; return max > p ? max : p; }
public static void main(String[] args){ Demo05 demo05 = new Demo05(); demo05.test(1,2,3,4,5); } public void test(int x,int...i){ System.out.println(x[0]); // 1 System.out.println(i[0]); // 2 System.out.println(i[1]); // 3 System.out.println(i[2]); // 4 System.out.println(i[3]); // 5 }
public static void main(String[] args){ System.out.println(f(5)); } public static int f(int n){ if (n == 1){ System.out.println(1); return 1; }else{ System.out.print(n + "*" + "f" + "("+(n-1)+")"+"*"); return n * f(n-1); } }
一维数组: int[] x 或者 int x[] 二维数组: int[][] y 或者 int[] y[] 或 int y[][]
一.数组的概述
int[ ] array = null; 声明时候数组并不存在 只有一个名字 只在栈中不在堆中,堆还是空的
- array = new int [10]; 数组创建在了堆中 在堆里面分配了一片连续的内存空间 定义了大小,这个空间就是array的名字 空间被分成10个小份元素,都是int类型,堆里就有了int对象
- 堆里面的连续的元素内存空间会有首地址,首地址值通常用十六进制数表示,然后把地址值赋给栈空间的array,栈空间的array通过地址值就能**(调用)**找到堆空间的创建的数组,他俩就联系起来了
array[0] = 1; …
创建完的数组中,每个元素都有初始化值,数组元素数字、字符类型默认值为0,字符串(String)类型为null,用角标的方式去调用数组中指定元素然后手动赋值覆盖掉原值
ArrayIndexOutOfBoundsException 数组下标越界
String[] arr6 = new String[]{"Tom","Jerry","Jim"}; // 静态初始化
数组元素的默认初始化值:
整型是:0
浮点型是:0.0
char(字符)型是:数字 0 或 ‘\u0000’,而非 字符 ‘0’
Boolean型是 false
String(字符串)类型是 null
后面面向对象中的类的属性的默认初始化值也是一样的
public static void main(String[] args){ // 静态初始化 int[] arr = new int[]{1,2,3,4,5}; System.out.println(arr[0]); System.out.println("=========="); // 动态初始化 String[] arr1 = new String[4]; // 用数组元素角标调用数组,给元素赋值 arr1[1] = "李华"; arr1[2] = "张三"; System.out.println(arr1[0]); System.out.println(arr1[1]); // 数组存放在堆中的内存空间的首地址发生改变 // 以后见到new 堆空间就要重新开辟 重新给arr1动态初始化 // arr1变量已经指向新的数组,旧的数组将被垃圾回收机制在不定时间回收,运用引用计数算法 // 当main方法执行完毕,arr1先出栈,新的数组变成垃圾被回收,最后arr出栈的数组也被垃圾 // string 是放在常量池里的 arr1 = new String[3]; System.out.println(arr1[2]); }
public static void main(String[] args){ System.out.println("请输入学生人数:"); Scanner scanner = new Scanner(System.in); // 存入学生人数 int number = scanner.nextInt(); // new一个学成绩数组,存入学生成绩 int[] scores = new int[number]; System.out.println("输入" + number + "个学生成绩"); // 给数组元素赋值 for (int i = 0; i < scores.length; i++){ scores[i] = scanner.nextInt(); } // 获取数组元素的最大值,最高分 int maxScore = 0; for (int i = 0; i < scores.length; i++){ if (maxScore < scores[i]){ maxScore = scores[i]; } } // 根据每个学生成绩的和最高分的差值,得到成绩的等级,并输出分数和成绩 char level; for (int i = 0; i < scores.length; i++){ if (maxScore - scores[i] <= 10){ level = 'A'; }else if (maxScore - scores[i] <= 20){ level = 'B'; }else if (maxScore - scores[i] <= 30){ level = 'C'; }else{ level = 'D'; } System.out.println("第" + i + "个学生成绩的等级是" + level + "成绩是" + scores[i]); } }
public static void main(String[] args){ System.out.println("请输入学生人数:"); Scanner scanner = new Scanner(System.in); int number = scanner.nextInt(); // new 一个学生成绩数组 存入 int[] scores = new int[number]; System.out.println("请输入" + number + "个学生成绩"); int maxScore = 0; for (int i = 0; i < scores.length; i++){ scores[i] = scanner.nextInt(); if (maxScore < scores[i]){ maxScore = scores[i]; } } char level; for (int i = 0; i < scores.length; i++){ if (maxScore - scores[i] <= 10){ level = 'A'; }else if (maxScore - scores[i] <= 20){ level = 'B'; }else if (maxScore - scores[i] <= 30){ level = 'C'; }else{ level = 'D'; } System.out.println("第" + (i+1) + "个学生的成绩等级 " + level + " 成绩是 " + scores[i]); } }
public static void main(String[] args){ int[] arrs = {1,2,3,4,5}; // 后面arrays代表一个数组,前面的变量代表数组里的每一个元素 // 增强型的for循环,jdk1.5以上版本特性,没有下标,适合打印输出 /*for (int array : arrays){ // arrays代表数组,array代表数组元素 System.out.println(array); }*/ int[] reverse = reverse(arrs); // 把反转的数组返回一个结果,这结果是一个数组 printArray(reverse); // 实参 } public static int[] reverse(int[] arrays){ // int[] 返回int数组类型 int[] result = new int[arrays.length]; // 创建一个结果数组存放要传入的数组 for (int i = 0,j = arrays.length-1; i < arrays.length; i++,j--){ result[j] = arrays[i]; } return result; // 返回这个方法的结果数组 } public static void printArray(int[] arrays){ // 形参 for (int i = 0; i < arrays.length; i++){ System.out.print(arrays[i]+" "); } }
public static void main(String[] args){ int[] arrs = new int[]{1,2,3,4,5}; reverse(arrs); } public static void reverse(int[] arrays){ for (int i = arrays.length - 1; i >= 0; i--){ System.out.println(arrays[i]); } }
- 二维数组的使用
- 规定: 二维数组分为外层数组元素,内层数组的元素
int[][] arr = new int[4][3];
外层元素: arr[0],arr[1]等
内层元素: arr[0][0], arr[1][2]等- 二维数组的默认初始化值
- 针对于初始化方式一,例如: int[][] arr = new int[4][3];
外层元素初始化值为: 地址值
内层元素初始化值为: 与一维数组初始化值相同- 针对初始化方式er" 比如: int[][] arr = new int[4][];
外层元素初始化值为: null
内层元素初始化值为: 不能调用,空指针异常,否则报错
// 二维数组声明和初始化 // 静态初始化 int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}}; // 动态初始化1 String[][] arr2 = new String[3][2]; // 动态初始化2 String[][] arr3 = new String[3][]; // 这样写也正确: int[] arr4[] = new int[][]{{1,2,3},{4,5},{6,7,8}}; int[] arr5[] = {{1,2,3},{4,5},{6,7,8}}; // 错误写法: // String[][] arr6 = new String[][4]; // String[4][3] arr7 = new String[][]; // int[][] arr8 = new int[4][3]{{1,2,3},{4,5},{6,7,8}};
// [4][2] 四行两列 /* 1,2 arr[0] 3,4 arr[1] 5,6 arr[2] 7,8 arr[3]*/ // 二维数组的元素是一维数组 public static void main(String[] args){ int[][] arr = new int[][]{{1,2},{3,4},{5,6},{7,8}}; printArray(arr[0]); // 打印第一行元素,1 2 System.out.println(); System.out.println(arr[0][1]); // 打印第一行第二列元素, 2 System.out.println(arr.length); // 打印数组长度,也就是一维数组行数,4 System.out.println(arr[0].length); // 第一行一维数组的元素个数,2 System.out.println("=========="); // 二维数组遍历 for (int i = 0; i < arr.length; i++){ for (int j = 0; j < arr[i].length; j++){ System.out.println(arr[i][j]); } } } public static void printArray(int[] arrays){ for (int i = 0; i < arrays.length; i++){ System.out.println(arrays[i]); } }
int[][] arrays = new int[][]{{1, 2}, {3, 4}, {5, 6}}; for (int[] array : arrays) { for (int element : array){ System.out.print(element+" "); } }
int[][] arr1 = new int[4][];
arr1[1] = new int[]{1,2,3};
arr1[2] = new int[4]
arr1[2][1] = 30;
int[] x,y[];
等同于 int[] x, int[] y[];
int x = 1; double y = x;
- a: no int型的数 != 二维数组类型
- b: yes 二维数组的元素 = 一维数组类型
- c: no int型的数 != 一维数组类型
- d: no
- e: yes int型的数 = int型的数
- f: no 一维数组类型 ≠ 二维数组类型 (类型不同,就算同是地址也不能赋值)
public static void main(String[] args){ int[] a = {115,6665,15,4633,452}; System.out.println(a); // 数组地址 // 打印数组元素 System.out.println(Arrays.toString(a)); // 转换成字符串 // printArray(a); Arrays.sort(a); // 数组进行排序:升序 System.out.println(Arrays.toString(a)); // a - 要填充的数组 // val - 要存储在数组所有元素的值 /* Arrays.fill(a,10); // 给数组填充赋值 System.out.println(Arrays.toString(a));*/ Arrays.fill(a,1,3,0); // 左闭右开区间 之间的元素被填充 System.out.println(Arrays.toString(a)); } public static void printArray(int[] arr){ for (int i = 0; i < arr.length; i++){ if (i == 0){ System.out.print("["); } if (i == arr.length - 1){ System.out.print(arr[i] + "]"); }else{ System.out.print(arr[i] + ", "); } } }
1.数组元素的赋值:
public static void main(String[] args) { System.out.println("输入杨辉三角的行数:"); Scanner scan = new Scanner(System.in); // 创建键盘输入数据的对象 int num = scan.nextInt(); // 接收键盘输入的数据 int[][] yangHui = new int[num][]; // 给每行数组赋值 for (int i= 0;i < yangHui.length;i++){ yangHui[i] = new int[i+1]; // 每行创建数组元素对象 yangHui[i][0] = yangHui[i][i] = 1; // 数组每行元素第一个和最后一个赋值为1 // 从第二行开始赋值 if (i > 1){ for (int j = 1;j < yangHui[i].length - 1;j++){ yangHui[i][j] = yangHui[i-1][j] + yangHui[i-1][j-1]; } } } // 遍历杨辉三角 for (int i = 0;i < yangHui.length;i++){ for (int j = 0;j < yangHui[i].length;j++){ System.out.print(yangHui[i][j] + "\t"); } System.out.println(); } scan.close(); }
2.求数值型数组中元素的最大值,最小值,平均数,总和等
public static void main(String[] args) { int[] arr = new int[10]; for (int i = 0;i < arr.length;i++){ arr[i] = (int) (Math.random() * (99 - 10 + 1) + 10); } // 遍历数组 for (int i = 0; i < arr.length; i++){ System.out.print(arr[i] + "\t"); } System.out.println(); // 求数组最大值 int maxValue = arr[0]; // 假如等于0 当数组为负数时,0就不适用了 for (int i = 1;i < arr.length;i++){ if (maxValue < arr[i]){ maxValue = arr[i]; } } System.out.println("最大值为:" + maxValue); // 求数组最小值 int minValue = arr[0]; for (int i = 1; i < arr.length; i++){ if (minValue > arr[i]){ minValue = arr[i]; } } System.out.println("最小值为:" + minValue); //求数组总和 int sum = 0; for (int i = 0; i < arr.length; i++){ sum = sum + arr[i]; } System.out.println("总和为:" + sum); // 求数组平均数 int avgValue = sum / arr.length; System.out.println("平均数为:" + avgValue); }
3.数组的复制,反转,查找(线性查找,二分查找)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J5RzPgkF-1630720147806)(https://upload-images.jianshu.io/upload_images/24940810-3a94f134b0e57553.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]
public static void main(String[] args) { String[] arr = new String[]{"aa","bb","gg","hh","dd"}; // 数组的复制(区别于数组的赋值: arr1 = arr) String[] arr1 = new String[arr.length]; for (int i = 0; i < arr1.length;i++){ arr1[i] = arr[i]; } // 数组的反转 // 方式一: // 交换长度如果不取一半,一半往后又继续交换回来了 /*for (int i = 0; i < arr.length / 2;i++){ String temp = arr[i]; arr[i] = arr[arr.length - i - 1]; arr[arr.length - i - 1] = temp; }*/ // 方式二: // 循环内定义一个头部一个尾部参数 /*for (int i = 0,j = arr.length - 1; i < j; i++,j--){ String temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; }*/ // 遍历 for (int i = 0;i < arr.length; i++){ System.out.print(arr[i] + "\t"); } System.out.println(); // 查找(或搜索) // 线性查找: String dest = "dd"; dest = "cc"; boolean isFlag = true; // 新定义一个标识为真 for (int i = 0; i < arr.length; i++){ // 字符串比较用 变量.equals(比较内容) int型比较直接用 == 就行 if (dest.equals(arr[i])){ System.out.println("找到了指定元素,位置为:" + i); isFlag = false; break; // 找到就退出循环,提高运行效率 } } if (isFlag){ System.out.println("没找到"); // 不能在for循环里写,没遍历完不能说没找到 } // 二分法查找: // 前提: 所要查找的数组必须有序 int[] arr2 = new int[]{-95,-35,-13,0,5,14,65,223,651}; int key = 5; int low = 0; // 初始的首索引 int high = arr2.length - 1; // 初始的尾索引 boolean isFlag1 = true; // 定义一个标识做判断是否进入if条件 while (low <= high){ int middle = (low + high) / 2; // middle如果放在while循环外 mddle永远是5(数组长度的一半那个值),所以不能放在外面 if (key == arr2[middle]){ System.out.println("找到了,索引为:" + middle); isFlag1 = false; break; // 找到后退出while循环 }else if (key < arr2[middle]){ high = middle - 1; }else{ // key > arr2[middle] low = middle + 1; } } if (isFlag1){ System.out.println("没找到"); } }
4.数组元素的排序算法
public static void main(String[] args){ int[] arr = new int[]{43,32,76,-98,0,64,33,-21,32,99}; int[] sort = sort(arr); System.out.println(Arrays.toString(sort)); } public static int[] sort(int[] arrays){ int temp = 0; // 循环的轮数 for (int i = 0; i < arrays.length - 1; i++){ // 每两个数比较的次数 for (int j = 0; j < arrays.length - 1 - i; j++){ if (arrays[j] > arrays[j+i]){ temp = arrays[j]; arrays[j] = arrays[j+1]; arrays[j+i] = temp; } } } return arrays; }
public static void main(String[] args) { // 创建一个二维数组 11*11 0:没有棋子 1:黑棋 2:白棋 int[][] array1 = new int[11][11]; array1[1][2] = 1; array1[2][3] = 2; // 输出原始数组 for (int[] arr1 : array1) { for (int element : arr1) { System.out.print(element+"\t"); } System.out.println(); } System.out.println("=================="); // 转换为稀疏数组保存 // 获取有效值的个数 int sum = 0; for (int i = 0;i < 11;i++){ for (int j = 0;j < 11;j++){ if (array1[i][j] != 0){ sum++; } } } System.out.println("有效值个数:" + sum); System.out.println("============="); //创建一个稀疏数组的数组 int[][] array2 = new int[sum+1][3]; // 稀疏数组的栏 array2[0][0] = 11; // 稀疏数组存的行数 array2[0][1] = 11; // 数组存的列数 array2[0][2] = sum; // 有效值的个数 // 遍历二维数组,将非零的值,存放在稀疏数组中 int count = 0; for (int i = 0;i < array1.length;i++){ for (int j = 0;j < array1[i].length;j++){ if (array1[i][j] !=0){ count++; // 计数作用 array2[count][0] = i; array2[count][1] = j; array2[count][2] = array1[i][j]; } } } // 输出稀疏数组 System.out.println("稀疏数组"); for (int i = 0;i < array2.length;i++){ System.out.println(array2[i][0]+"\t"+array2[i][1]+"\t"+array2[i][2]+"\t"); } System.out.println("==============="); // 读取稀疏数组 int[][] array3 = new int[array2[0][0]][array2[0][1]]; // 读取稀疏数组的行和列 // 给其中的元素还原它的值 for (int i = 1;i < array2.length;i++){ // i从1开始遍历,因为第0行是稀疏数组的头部信息 array3[array2[i][0]][array2[i][1]] = array2[i][2]; } System.out.println("还原数组:"); for (int i = 0;i < array3.length;i++){ for (int j = 0;j < array3[i].length;j++){ System.out.print(array3[i][j]+"\t"); } System.out.println(); } }
// 创建一个二维数组 int[][] array1 = new int[5][6]; array1[1][3] = 2; array1[4][2] = 6; for (int i = 0;i < array1.length;i++){ for (int j = 0;j < array1[i].length;j++){ System.out.print(array1[i][j]+"\t"); } System.out.println(); } // 获取有效值 转换为稀疏数组 int sum = 0; for (int i = 0;i < array1.length;i++){ for (int j = 0;j < array1[i].length;j++){ if (array1[i][j] != 0){ sum++; } } } System.out.println("有效值:"+sum); System.out.println("================"); // 创建稀疏数组 int[][] array2 = new int[sum+1][3]; array2[0][0] = 5; // 第一行第一列 array2[0][1] = 6; // 第一行第二列 array2[0][2] = sum; int count = 0; for (int i = 0;i < array1.length;i++){ for (int j = 0;j < array1[i].length;j++){ if (array1[i][j] != 0){ count++; array2[count][0] = i; array2[count][1] = j; array2[count][2] = array1[i][j]; } } } System.out.println("稀疏数组:"); for (int i = 0;i < array2.length;i++){ // 将稀疏数组 System.out.println(array2[i][0] + "\t" + array2[i][1] + "\t" + array2[i][2] + "\t"); } // 读取稀疏数组 int[][] array3 = new int[array2[0][0]][array2[0][1]]; for (int i = 1;i < array2.length;i++){ array3[array2[i][0]][array2[i][1]] = array2[i][2]; } System.out.println("输出还原数组:"); for (int i = 0;i < array3.length;i++){ for (int j = 0;j < array3[i].length;j++){ System.out.print(array3[i][j]+"\t"); } System.out.println(); }
Java面向对象学习三条主线:
1.Java类及类的成员:属性,方法,构造器;代码块,内部类
2.面向对象的三大特征:封装性,继承性,多态性,(抽象性)
3.其他关键字:this,super,static,final,abstract,interface,package,import
类: 是对一类事物的描述, 抽象的, 概念上的内容
对象: 实实在在存在的一个个体. new出来的东西,在内存当中存在的, 在内存中真正的创建了一个对象,占据了内存一定空间
对象: 是由类派生(new)出来的
面向对象编程(Objected-Oriented-Programming,OOP),Java的核心思想
面向对象编程的本质是: 以类的方式组织代码,以对象的形式组织(封装)数据.
抽象 把相似的抽取出来
三大特性:
从认识论角度考虑是先有对象后有类. 对象,是具体的事物. 类,是抽象的, 是对对象的抽象
从代码运行角度考虑是先有类后有对象. 类是对象的模板.
值传递
// 值传递 public static void main(String[] args){ int i = 1; System.out.println(i); Demo04.change(i); System.out.println(i); i = Demo04.change1(i); System.out.println(i); } // 返回值为空 public static void change(int a){ a = 10; } // 返回值不为空 public static int change1(int a){ a = 10; return a; }
public class Demo05 { // 一个类可以有多个public class 但是可以有多个class // 引用传递: 对象,本质还是值传递 public static void main(String[] args) { // Person是一个引用,指向的是堆里面的对象 Person person = new Person(); // 实例化Person对象 System.out.println(person.name); // null // Demo05.change(person); change(person); // 引用传递传递的是对象的地址 System.out.println(person.name);// dijia // 变量名对应的内存地址不一样 // 值传递,传递后的值被改了不影响原变量 // 因此只是将方法中的变量指向了字符串,并未改变main方法原变量的引用 } public static void change(Person person) { // person是一个对象:指向Person这个类 // 或是 Person person = new Person();这是个具体的人,可以改变属性! person.name = "dijia"; } } // 定义一个Person类,有一个属性: name class Person { String name; }
面向对象思想的体现一 ,类和对象的创建和执行操作(面向对象思想落地地实现):
1.创建类,设计类的成员
2.创建类的对象
3.通过"对象.属性"或"对象.方法()"调用对象的结构
二,如果创建了一个类的多个对象,每个对象都独立的拥有一套类的属性(无static关键字的)
意味着,如果我们修改一个对象的属性a,不影响另一个属性a的值.(static为可共享属性)
// 测试类 public class PersonTest { // main方法作为程序入口 public static void main(String[] args) { // 创建Person类的对象=类的实例化=实例化类 Person p1 = new Person(); // 类是对象的类型,对象是类的实例,Person是引用的变量类型 // 调用对象的(功能和行为)结构: 属性和方法 // 调用属性: "对象.属性;" p1.name = "tom"; p1.isMale = true; System.out.println(p1.name); // 调用方法: "对象.方法();" p1.eat(); p1.sleep(); p1.talk("Chinese"); System.out.println("================"); Person p2 = new Person(); System.out.println(p2.name); // null System.out.println(p2.isMale); // false System.out.println("==================="); // Person p3 = p1; // p1对象的地址值赋给了p3,导致p1和p3指向了堆空间中的同一个对象实体 System.out.println(p3.name); // tom p3.age = 10; System.out.println(p1); System.out.println(p3); System.out.println(p1.age); // 10 } } // 创建类,设计类的成员:包括成员方法,成员变量 class Person{ // 属性= 成员变量= 域,字段 String name; int age = 1; boolean isMale; // 设计方法:行为 public void eat(){ System.out.println("人可以吃饭"); } public void sleep(){ System.out.println("人可以睡觉"); } public void talk(String language){ System.out.println("人可以说话使用:" + language); }
类中属性的使用
属性(成员变量) vs 局部变量
public static void main(String[] args) { User u1 = new User(); System.out.println(u1.name); System.out.println(u1.age); System.out.println(u1.isMale); u1.talk("中文"); u1.eat(); } } class User{ // 属性(成员变量) String name; // private权限小,出了定义的这个类就不能调了 public int age; // public权限大,在外的就能调 boolean isMale; public void talk(String language){ // language:形参(局部变量) System.out.println("我们使用" + language + "交流"); } public void eat(){ String food = "烙饼"; // (声明)定义在方法内的变量叫局部变量 System.out.println("北方人吃" + food); }
关于垃圾回收器: GC
在Java语言中,垃圾回收器主要针对的是堆内存.
当一个Java对象没有任何引用指向该对象的时候,
GC会考虑将该垃圾数据释放回收掉.
/* 空指针异常 */ public class NullPointerTest { public static void main(String[] args) { // 创建客户对象 Customer1 c1 = new Customer1(); // 访问这个客户对象 System.out.println(c1.id); // 重新给id赋值 c1.id = 242; System.out.println(c1.id); c1 = null; // NullPointerException 空指针异常 // 编译器没问题,因为编译器只检查语法,编译器发现c是Customer类型, // Customer类型中由id属性,所以可以: 调用c.id,语法过了, // 但是运行的时候需要对象的存在,但是对象丢失,就只能出现异常 System.out.println(c1.id); } } // 客户类 class Customer1{ // 客户id属性 int id; // 成员变量中的实例变量,应该先创建对象,再通过"引用."的方式访问 }
public class StudentTest1 { public static void main(String[] args) { // 声明自定义类Student类型的对象数组 Student1[] stus = new Student1[20]; // 类似于String[] arr = new String[]; for (int i = 0;i < stus.length;i++){ // 给数组元素赋值 stus[i] = new Student1(); // 给Student对象的属性赋值 stus[i].number = (i + 1); // 年级: [1,6] // 随机数a~b公式: int value = (int)(Math.random() * (b - a + 1) - a) stus[i].state = (int)(Math.random() * (6 - 1 + 1) + 1); // 分数: [0~100] stus[i].score = (int)(Math.random() * (100 - 0 + 1)); } // 想在main方法里调用其他方法,要在main方法公共类里造一个当前类的对象, StudentTest1 test = new StudentTest1(); // 遍历学生数组 test.print(stus); /*for (int i = 0;i < stus.length;i++){ // stus[i].info(); System.out.println(stus[i].info2()); }*/ System.out.println("======================"); // 打印三年级(state值为3)的学生信息 test.searchState(stus,3); /*for (int i = 0;i < stus.length;i++){ if (stus[i].state == 3){ stus[i].info(); } }*/ System.out.println("========================"); // 使用冒泡排序按学生成绩排序,并遍历所有学生信息 /* for (int i = 0;i < stus.length - 1;i++){ for (int j = 0;j < stus.length - 1 - i;j++){ if (stus[j].score > stus[j+1].score){ // 这里要交换数组元素的对象!意思是把整个人交换 // 如果只交换成绩,学号和年级都没换,相当于"作弊" Student1 temp = stus[j]; stus[j] = stus[j+1]; stus[j+1] = temp; } } }*/ /*for (int i = 0;i < stus.length;i++){ System.out.println("学号:" + stus[i].number + "年级:" + stus[i].state + "成绩:"+ stus[i].score); }*/ } // 遍历Student1[]类型数组的操作 /** * @Description 遍历Student1[]类型数组的操作 * @author tiga * @date time * @param stus */ public void print(Student1[] stus){ // 传入Student1[]类型数组的形参 for (int i = 0;i < stus.length;i++){ stus[i].info(); } } // 查找某年级的学生信息 /** * * @Description 查找Student类型数组中指定年级的学生信息 * @author tiga * @date time * @param stus 要查找的数组 * @param state 要查找的年级 */ public void searchState(Student1[] stus,int state){ // 传入要找的那个数组和要找的年级为形参 for (int i = 0;i < stus.length;i++){ if (stus[i].state == state){ System.out.println(stus[i].info2()); } } } // 冒泡排序学生成绩,遍历学生信息 public void sort(Student[] stus){ for (int i = 0;i < stus.length - 1;i++){ for (int j = 0;j < stus.length - 1 - i;j++){ if (stus[j].score > stus[j+1].score){ Student temp = stus[j]; stus[j] = stus[j+1]; stus[j+1] = temp; } } } } } class Student1{ int number; // 学号 int state; // 年级 int score; // 成绩 public void info(){ System.out.println("学号:" + number + "年级:" + state + "成绩:" + score); } public String info2(){ return "学号:" + number + "年级:" + state + "成绩:" + score; } }
引用类型变量只能存储null或对象的地址值(含变量的类型).
一.理解"万事万物皆对象"
1.在Java语言范畴中,都将功能,结构等封装到类中,通过类的实例化,来调用具体的功能结构
Scanner,String
文件:File
网络资源: URL
2.涉及到Java语言与前端HTML,后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类,对象
二.内存解析的说明:
1.引用类型的变量,只可能存储两类值:null 或 地址值(含变量的类型)
三.匿名对象的使用
1.理解:创建的对象,没有显式的赋给一个变量名.即为匿名对象
2.特征: 匿名对象只能调用一次
3.使用: 可以将匿名对象放入方法里多次调用
在调用方法里new完Phone这个类的对象,在堆里产生的空间也会有一个地址值,调用时new的对象其实是赋值给了定义类里的方法里作为形参,形参又是个局部变量,且该变量会存入栈中,相当于把new Phone这个类出来的对象的地址值赋给了形参,只要是赋给了变量,对象就可以多次使用,从而形参就指向了堆中new的新对象, 就能通过新对象的地址调用其他方法, 这时调用的是同一个匿名对象,这相当于把匿名的对象赋给了有名的对象(形参).
public class InstanceTest { public static void main(String[] args) { Phone p = new Phone(); // p就是Phone对象的变量名 // p = null; System.out.println(p); p.sentEmail(); p.playGame(); // 匿名对象 // 两者调用的不是同一对象 new Phone().sentEmail(); new Phone().playGame(); new Phone().price = 2000; new Phone().showPrice(); // 0.0 System.out.println("======================"); // 匿名对象的使用 PhoneMall mall = new PhoneMall(); mall.show(new Phone()); // 理论上是匿名 ShowAddress add = new ShowAddress(); add.printAdd(new PhoneMall()); } } class ShowAddress{ public void printAdd(PhoneMall phone){ System.out.println(phone); } } class PhoneMall{ public void show(Phone phone){ // 实际上形参就是匿名函数的名字 phone.sentEmail(); phone.playGame(); } } class Phone{ double price; // 价格 public void showPrice(){ System.out.println("手机价格是:" + price); } public void sentEmail(){ System.out.println("发送邮件"); } public void playGame(){ System.out.println("玩游戏"); } }
- 当在方法中定义了基本数据类型的局部变量,其变量存放在栈中,给变量赋值的数字就是变量在栈内存中存放的东西, 变量之间的赋值传递, 也是传递数字.
int m = 10; int n = m; // n == 10
- 当在方法中定义了引用类型的局部变量,其变量也是存放在栈中,但是变量赋给的值的地址值, 所以当同类型变量之间赋值传递, 是传递地址,而不是数字.
一.方法的形参的传递机制: 值传递
1.形参: 方法定义时,声明的小括号内的参数
2.实参,方法调用时,实际传递给形参的数据,可以是具体数也可以是变量
二.值传递机制: 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值.
1.m和n没有换成的原因: 在栈中,先从main方法进来,main方法中定义的m, n分别赋值10, 20;
2.通过对象v调swap方法,v就不往里面写了,当调用swap方法时候,将上面实参m, n表示数据的值,赋给了下面swap方法的形参m, n(新定义的),这两个形参还要在栈中提供,形参m, n分别是实参赋值过来的,也是10和20,此时的m, n 是swap方法中的;
3.接着v调用swap方法就进入方法执行,一进去又声明新变量temp,temp拿了形参m赋的值,接着形参n的值给了m,接着又把temp给了n,最swap方法实现效果是把swap方法里的m和n交换,如果在方法里面输出,m和n就会交换,但是如果方法内不输出,swap方法执行完以后就销毁了(出栈), 销毁之后接着在main方法下面再输出,输出的m和n的值是main方法赋的值,因为swap方法出栈以后,输出的m和n保存的值是main里面定义的m和n两变量的值, main里面定义的变量在main的整个大括号区间里都是有效的,所以main里面输出的还是main里定义的值,所以两数没换成. 数组元素的值交换也是同理
public static void main(String[] args) { int m = 10; int n = 20; System.out.println(m + "," + n); ValueTransferTest1 test = new ValueTransferTest1(); test.swap(m,n); // 实参 /*int temp = m; m = n; n = temp;*/ System.out.println(m + "," + n); // 10, 20 } public void swap(int m,int n){ // 新变量实参传入的形参 int temp = m; m = n; n = temp; // System.out.println(m + "," + n); }
值传递机制: 针对引用数据类型
静态方法调用非静态方法要先new一个对象
静态方法调用静态方法直接调用
非静态方法调用非静态方法直接调用
内存分析
1.从main方法进来,在栈中new了一个data变量,也在堆空间中new了一个对象,该对象会有个地址值,并把地址值赋值给栈空间的data变量,通过地址值,栈空间中的data变量指向堆空间中的对象实体
2.接着下一步,data(对象)变量调用Data类中定义的变量m, n,一开始m, n的初始值都为0,通过对象调属性改了m, n的值,此时输出就是10, 20.
3.接着新建的对象去调swap方法,顺便把引用类型data传入作为形参,传入的引用类型data是上面的实参,所以形参是引用类型就存的是地址值,形参在栈中加载,相当于把main方法中data的地址值复制了一份,形参有了地址值后,他就指向堆空间中同一对象实体
4.进入swap方法体,通过data(形参)变量调用m的值,赋给一个swap方法内部声明的局部变量temp,temp也加载在栈中,data的n的值赋给data的m,temp的值又赋给了data的n,至此方法执行结束,结束后,swap方法定义的temp和data变量就出栈了,出栈后形参data的指针就没了,但是堆中对象还在,还有实参data的指向,这样判断堆中对象就不是垃圾,不能回收了.
5.回到main方法接着执行输出 data.m和data.n, 这两data变量是实参data, m和n的值就交换了
面向对象的特征一: 封装和隐藏
一.问题的引入:
当我们创建一个类的对象以后,我们可以童工"对象.属性"的方式,对对象的属性进行赋值,这里,赋值操作要瘦到属性的数据类型和存储范围的制约
除此之外,没有其他制约条件,但是在实际问题中,我们往往需要给属性赋值加入额外的限制调价.这个特条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加.(比如: setLegs())
同时,我们需要避免用户再使用"对象.属性"的方式对属性进行赋值.则需要将属性声明为私有的(private)
–>此时,针对于属性就体现了封装性
二.封装性的体现之一(不等同于封装性):
将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值
拓展: 封装性的体现: 1.如上 2.不对外暴露的私有的方法 3.单例模式: 把构造器私有化
三.封装性的体现,需要权限修饰符来配合
1.Java规定的4种权限(从小到大排列): private,缺省,protected,public
2.4种权限可以用来修饰类及类的内部结构: 属性,方法,构造器,内部类,(代码块不行)
3.具体的,4中权限都可以用来修饰类的内部结构:属性,方法,构造器,内部类
修饰类的话,只能用: 缺省,public,不能用private
总结封装性: Java提供了4中权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在被调用时的可见性的大小
体现一: 将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值
体现二: 不对外暴露的私有的方法
体现三:单例模式(将构造器私有化,外边不能随便调构造器, 里面自己只造一个对象,大家都只拿一个对象用)
体现四: 如果不希望类在包外被调用,可以将类设置为缺省的.
public class AnimalTest { public static void main(String[] args) { Animal a = new Animal(); a.name = "大黄"; // a.age = 1; // 将属性私有化后不能直接调用,要通过public方法调用 // a.legs = 4; // 作用域不可见 The field Animal.legs is not visible a.show(); // 谁调的show方法,方法里显示的属性值就是谁的 a.setLegs(-6); // a.legs = -4; // The field Animal.legs is not visible a.show(); } } class Animal{ String name; private int age; // private好处:setLegs提供方法让legs赋值并加入判断条件,还能把直接调属性给禁掉 // 此时就能达到对 legs属性的封装,相当于这个属性没有对外暴露 private int legs; // 腿的数量 限制为私有权先,可见但类外面不能调用 public void setLegs (int l){ if (l >= 0 && l % 2 == 0){ legs = l; }else{ legs = 0; // 另一种写法,抛出一个异常(暂时没讲) } } public int getLges(){ return legs; } public void eat(){ System.out.println("动物进食"); } public void show (){ System.out.println("name = " + name + ",age = " + age + ",legs = " + legs); } // 提供关于属性age的get和set方法 public int getAge(){ return age; } public void setAge(int a){ age = a; } }
public class PersonTest { public static void main(String[] args) { Person p1 = new Person(); // p1.age = 1; // age私有化后不能直接调用,编译不通过 p1.setAge(12); System.out.println("年龄为:" + p1.getAge()); } } public class Person { private int age; public void setAge(int a){ if (a < 0 || a > 130){ // throw new RuntimeException("传入数据非法"); // [[抛异常 System.out.println("传入数据非法"); return; // 结束方法 } age = a; } public int getAge(){ return age; } // 绝对不要把设置和获取的方法合起来写! 这些写方法没意义 /*public int doAge(int a){ age = a; return a; }*/ }
- 类的结构之三,构造器(或构造函数(c++)或构造方法但又不同于方法,constructor)的使用
construct: 建设,建造. construction constructor: 建设者- 一.构造器的作用:
1.创建对象
2.初始化对象的属性- 二.说明:
1.如果没有显式的定义类的构造器的话,则系统默认提供默认无参构造器
2.定义构造器的格式(不同于方法): 权限修饰符 类名(形参列表){}
3.一个类中定义多个构造器,彼此构成重载
4.一旦我们显式的定义了类的构造器之后,系统就不在提供默认的无(空)参构造器(可用国家贫困补贴举例)
5.一个类中,至少会有一个构造器.(相当于给我们造对象的能力,有构造器才能造对象)(可能是默认的也可是自己写的)
public class PersonTest { public static void main(String[] args) { // 创建类的对象(构造器的使用): new + 构造器 (构造器和类同名) Person p = new Person(); // 自己定义了显式的构造器 p.eat(); Person p1 = new Person("tom"); System.out.println(p1.name); } } class Person{ int age; String name; // 构造器 public Person(){ // 可以用于初始化 比如实例化这个类时就需要传值,而不是在调用方法才传值 // 构造器里的代码在new对象的时候就执行了 System.out.println("Person()....."); } // 构造器的重载 public Person(String n){ // 形参的作用 初始化造的对象当前的属性 name = n; // name: 当前正在创建的对象的属性 } public Person(String n, int a){ name = n; age = a; } public void eat(){ System.out.println("人吃饭"); } public void study(){ System.out.println("人睡觉"); } }
1.创建程序,在其中定义两个类:Person和PersonTest类.定义如下:
用setAge()设置热的合法年龄(0~130),用getAge()返回人的年龄
2.1.在前面定义的Person类中添加构造器,利用构造器设置所有人的age属性初始值都为18
2.2.修改上题中类和构造器,增加name属性,使得每次创建Person对象的同时初始化对象的age属性值和name属性值
3.如果类中提供了至少一个构造器,但是没有提供空参构造器,那么构造对象时如果不提供参数就是不合法的.也就是创建没有形参的对象会报错
/* * 在PersonTest类中实例化Person类的对象b * 调用setAge()和getAge()方法,体会Java的封装性 */ public class PersonTest { public static void main(String[] args) { Person p1 = new Person(); // p1.age = 1; // age私有化后不能直接调用,编译不通过 p1.setAge(12); // p1.getAge(); // age == 18 System.out.println("年龄为:" + p1.getAge()); Person p2 = new Person("tom", 21); // 属性私有化后只能通过方法来调用 System.out.println("name: " + p2.getName() + ", age: " + p2.getAge()); } } 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 < 0 || a > 130){ // throw new RuntimeException("传入数据非法"); // 抛异常 System.out.println("传入数据非法"); return; // 结束方法 } age = a; } public int getAge(){ return age; } // 体现了封装性 public void setName(String n){ name = n; } public String getName(){ return name; } // (错误写法)绝对不要把设置和获取的方法合起来写! 这些写方法没意义 /*public int doAge(int a){ age = a; return a; }*/ }
/* * 编写两个类,TriAngle和TriAngleTest,其中TriAngle类中声明私有的底边长base和高height,同时声明公共方法访问私有变量. * 此处,提供类必要的构造器.另一个类中使用这些公共方法,计算三角形的面积 */ public class TriAngleTest { public static void main(String[] args) { TriAngle t1 = new TriAngle(); t1.setBase(3.2); // 相当于传入实参 t1.setHeight(4.66); System.out.println("base: " + t1.getBase() + ", height: " + t1.getHeight()); // 构造器一方面可创建对象,同时可给相应对象的属性赋值 TriAngle t2 = new TriAngle(5.1, 4.6); System.out.println("base: " + t2.getBase() + ", height: " + t2.getHeight()); } } public 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; } }
1.默认初始化(类属性默认值)
2.显式初始化(给类中属性赋值)
3.构造器中初始化(赋值)
=上面三个操作只能执行一次,下面的可以反复执行===
4.未封装通过"对象.属性"的方式,赋值或封装后通过"对象.方法名()",赋值
以上操作的先后顺序: 1 - 2 - 3 - 4,从后往前覆盖,前面的都作为过程出现
public class UserTest { public static void main(String[] args) { User u = new User(); System.out.println(u.age); User u1 = new User(2); u1.setAge(3); System.out.println(u1.age); } } class User{ String name; int age = 1; public User(){ } public User(int a){ age = a; } public void setAge(int a){ age = a; } }
this关键字的使用:
- 1.this可用来修饰: 属性,方法,构造器
- 2.this修饰属性和方法:
this理解为: 当前对象或当前正在创建的对象
- 2.1.在类的方法中,我们课使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法.
但是,通常情况下,我们都选择省略"this. ".特殊情况下,如果方法的形参和类的属性同名时,必须显式的使用"this.变量"的方式,表明此变量是属性,而非形参.- 2.2.在类的构造器中,我们可使用"this.属性"或"this.方法"的方式,调用当前正在创建的对象属性或方法,但是,通常情况下,都选择省略"this.",特殊情况下,如果构造器的形参和类的属性同名时,必须显式的 使用"this.变量"的方式,表明此变量是属性,而非形参.
public class PersonTest { public static void main(String[] args){ Person p1 = new Person(); // 使用默认的空参构造器 p1.setAge(1); System.out.println(p1.getAge()); p1.eat(); } } class Person{ private String name; // 类的成员变量(属性) private int age; public Person(){ this.eat(); // 调当前正在创建的对象的eat方法 } // 构造器中的this: 当前正在创建的对象 public Person(String name){ this.name = name; // 当前正在创建的对象的属性 } public Person(int age){ this.age = age; } public Person(String name, int age){ this.name = name; this.age = age; } public void setName(String name){ // 属性和形参(局部变量)同名不报错因为地位不同,一个在类中一个在方法中 this.name = name; // 就近原则,优先考虑近的变量名 } public String getName(){ return this.name; } public void setAge(int age){ // age = 1 // age = age; // 1 = 1,跟属性age无关了 // this: 可理解为当前对象,相当于p1 this.age = age; // 当前对象的属性/方法 通过对象调方法或属性都用点 } public int getAge(){ return this.age; } public void eat(){ System.out.println("人吃饭"); this.study(); } public void study(){ System.out.println("人学习"); } }
this关键字的使用:
1.this可用来修饰: 属性,方法,构造器
2.this修饰属性和方法:
this理解为: 当前对象或当前正在创建的对象
2.1.在类的方法中,我们课使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法.
但是,通常情况下,我们都选择省略"this. “.特殊情况下,如果方法的形参和类的属性同名时,
必须显式的使用"this.变量"的方式,表明此变量是属性,而非形参.
2.2.在类的构造器中,我们可 使用"this.属性"或"this.方法"的方式,调用当前正在创建的对象属性或方法,
但是,通常情况下,都选择省略"this.”,特殊情况下,如果构造器的形参和类的属性同名时,必须显式的
使用"this.变量"的方式,表明此变量是属性,而非形参.
3.this调用构造器
(1)在类的构造器中,可显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器
(2)构造器中不能通过"this(形参列表)“方式调用自己
(3)如果一个类中由n个构造器,则最多有n-1个构造器中使用了"this(形参列表)”
(4)规定: "this(形参列表)“必须声明当前构造器的首行
(5)构造器内部,最多只能声明一个"this(形参列表)”,用来调用其他的构造器
public class PersonTest { public static void main(String[] args){ Person p1 = new Person(); // 使用默认的空参构造器 p1.setAge(1); System.out.println(p1.getAge()); p1.eat(); System.out.println(); // 构造器多重调用也只是创建了一个对象,只是调用其他构造器时逻辑借用了其他构造器的逻辑 // 不管通过什么方式调用构造器,最终也只是造了一个对象 Person p2 = new Person("Harry", 20); System.out.println(p2.getAge()); System.out.println(p2.getName()); } } class Person{ private String name; // 类的成员变量(属性) private int age; public Person(){ // this.eat(); // 调当前正在创建的对象的eat方法 // this(); // 空参构造器不能调自己,会死循环,两个构造器也不能来回调 String info = "Person初始化时,需要考虑如下的1,2,3,4...(共40行代码)"; System.out.println(info); } // 构造器中的this: 当前正在创建的对象 public Person(String name){ this(); // 调用构造器的方法,参数是什么,就是调哪个构造器 this.name = name; // 当前正在创建的对象的属性 } public Person(int age){ this(); this.age = age; } public Person(String name, int age){ this(age); this.name = name; // 再初始化独立的name // this.age = age; 调用上面的构造器后可省略 } public void setName(String name){ // 属性和形参(局部变量)同名不报错因为地位不同,一个在类中一个在方法中 this.name = name; // 就近原则,优先考虑近的变量名 } public String getName(){ return this.name; } public void setAge(int age){ // age = 1 // age = age; // 1 = 1,跟属性age无关了 // this: 可理解为当前对象,相当于p1 this.age = age; // 当前对象的属性/方法 通过对象调方法或属性都用点 } public int getAge(){ return this.age; } public void eat(){ System.out.println("人吃饭"); this.study(); } public void study(){ System.out.println("人学习"); } }
public class CustomerTest { public static void main(String[] args) { Customer cust = new Customer("Jane", "Smith"); Account acct = new Account(1000, 2000, 0.0123); // 声明构造器 cust.setAccount(acct); // 银行办卡后得到了卡号 cust.getAccount().deposit(100); // 类变量的运用 cust.getAccount().withdraw(960); cust.getAccount().withdraw(2000); System.out.println("Customer [" + cust.getLastName() + "," + cust.getFirstName() + "] has a account: id is " + cust.getAccount().getId() + ", annualInterrestRate is" + cust.getAccount().getAnnualInterestRate() * 100 + "%, balance is " + cust.getAccount().getBalance()); } } public class Account { private int id; // 账号 private double balance; // 余额 private double annualInterestRate; // 年利率 // 构造器 public Account(int id,double balance,double annualInterestRate){ this.id = id; this.balance = balance; this.annualInterestRate = annualInterestRate; } public void setId(int id){ this.id = id; } public int getId(){ return this.id; } public void setBalance(double balance){ this.balance = balance; } public double getBalance(){ return this.balance; } public void setAnnualInterestRate(double annualInterestRate){ this.annualInterestRate = annualInterestRate; } public double getAnnualInterestRate(){ return this.annualInterestRate; } public void withdraw(double amount){ // 取钱 if (balance < amount){ System.out.println("余额不足,取钱失败"); return; // 和else作用相同 } balance -= amount; System.out.println("成功取出" + amount); } public void deposit(double amount){ // 存钱 if (amount > 0){ balance += amount; System.out.println("成功存入" + amount); } } } public class Customer { private String firstName; private String lastName; private Account account; // 构造器 public Customer(String f,String l){ this.firstName = f; this.lastName = l; } public String getFirstName(){ return this.firstName; } public String getLastName(){ return this.lastName; } public void setAccount(Account account){ this.account = account; } public Account getAccount(){ return this.account; } }
public class BankTest { public static void main(String[] args) { Bank bank = new Bank(); bank.addCustomer("Jane","Smith"); // 连续操作 可能会空指针,方法要有返回值才能连续操作 bank.getCustomer(0).setAccount(new Account(2000)); bank.getCustomer(0).getAccount().withdraw(500); double balance = bank.getCustomer(0).getAccount().getBalance(); System.out.println("客户:" + bank.getCustomer(0).getLastName() + "的账户余额为: " + balance); bank.addCustomer("万里","杨"); System.out.println("银行客户个数: " + bank.getNumberOfCustomers()); } } public class Customer { private String firstName; private String lastName; private Account account; // 构造器 public Customer(String f,String l){ this.firstName = f; this.lastName = l; } // get,set方法 public String getFirstName(){ return this.firstName; } public String getLastName(){ return this.lastName; } public void setAccount(Account acct){ this.account = acct; } public Account getAccount(){ return this.account; } } public class Account { private double balance; public Account(double init_balance){ this.balance = init_balance; } // 余额查询 public double getBalance(){ return this.balance; } // 存钱操作 public void deposit(double amt){ if (amt > 0){ balance = balance + amt; System.out.println("存款成功"); } } // 取钱操作 public void withdraw(double amt){ if (balance > amt){ balance = balance - amt; System.out.println("取钱成功"); }else{ System.out.println("余额不足"); } } } public class Bank { // 定义了变量,未初始化,但是属性是已经默认初始化了的,此时默认值为null private Customer[] customers; // 存放多个用户的数组 private int numberOfCustomers; // 记录客户的个数 // 构造器 public Bank(){ customers = new Customer[10]; // 先要给数组初始化空间 因为权限是private所以不能再测试类main里初始化 } // 添加客户方法 public void addCustomer(String f,String l){ // cust是customer类型变量,上面定义的数组也是customer类型的,所以可以赋值 Customer cust = new Customer(f, l); // customers[numberOfCustomers] = cust; // 可以理解为 customers[numberOfCustomers] = new Customer(f,l); 数组元素在构造器中静态赋值 // numberOfCustomers++; // customers = new Customer[10]; // 数组空间初始化不能写在这,因为,本来是是造构造器中造好一个数组后掉一个方法存一个人再调方法再存一个人,写在方法里变成,先调方法造好一个数组后再存一个人,再调一次方法又重新造一个数组再重新存一个人 customers[numberOfCustomers++] = cust; } // 获取客户个数的方法 public int getNumberOfCustomers(){ return numberOfCustomers; } // 获取指定位置上的客户的方法 public Customer getCustomer(int index){ // return customers[index]; // 不能这样写,可能报异常1.数组未初始化时可能空指针,2.数组初始化后可能会数组下标越界,3.index也许不会超出数组长度,但是大于实际存入的数组元素个数也不行. if (index >= 0 && index < numberOfCustomers){ // 索引值小于客户数,因为第一个客户放在了第0位 return customers[index]; } return null; } }
1.减少了代码的冗余,提高了代码的复用性
2.便于功能的扩展: 把子类都想扩展的功能直接声明在父类当中,子类又因为继承了,直接就可以拿到
3.为之后多态性的使用,提供了前提
class A extends B{}
A: 子类,派生类,subclass
B: 父类,超类,基类,superclass
2.1.体现: 一旦子类A继承父类B以后,子类A中就获取了父类B中声明的所有:属性,方法 (用来调用)
特别地,父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构
只有因为封装性的影响,使得子类不能直接调用父类的结构而已
2.2.子类继承父类以后,还可以声明自己特有的属性或方法,实现自己特有的功能的拓展
子类和父类的关系,不同于子集和集合的关系(父类有的子类一定有,子类有的父类不一定有)
1.一个父类可以被多个子类继承.
2.Java中**类的单继承性:**一个类只能有一个父类;(接口可以多继承)
3.子父类是相对的概念
4.子类直接继承的父类,称为: 直接父类;简介继承的父类称为:间接父类
5.子类继承父类后,就获取了直接父类以及所有间接父类中声明的属性和方法
特别声明是java.lang包下的Object类因为可能自己会创建同名的Object类
1.如果我们没有先是的声明一个类中的父类的话,则此类继承于java.lang.Object类
2.所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类
3.所有java类具有java.lang.Object类声明的功能