怎么学习Java:多想,多练
思想是学出来的,我给大家一个问题,如何来解决它,现在来说很多人是没有思路的
我要做的就是给大家这样一个思路,学的多了,练得多了,在遇到问题的时候,也就
逐渐的形成了这个解决问题的思维
为什么很多公司招有3-5年工作经验的开发人员,工资又高,是因为家有一老如有一宝
公司还是喜欢招年轻人的工作有动力。招有工作经验多的人是因为他在这么多年的工作
中遇到的问题多,解决的问题,他的经验就是他宝贵的财富。
Java语言介绍
Java是一种编程语言,如C++,C,PHP等。语言是沟通交流,传递信息的工具。
我与大家之间通过汉语交流,那么java就是人类与计算机之间沟通交流,传递信息的工具。
Java的三大平台
JavaSE Java的标准平台:包含了Java的基础的功能,学习的语法,内置的API方法
JavaEE Java的企业级应用平台:JavaSE的基础上,扩展了一些API,用于B/S结构的企业应用的开发
JavaME Java的移动应用平台:JavaSE缩微版,给嵌入式系统或移动端系统使用过时
Java语言特点
1.跨平台 平台-操作系统
任何平台上编写的Java程序,可以在另外的平台上执行
JDK Java的开发环境
JRE Java的运行环境 - Java虚拟机
java文件 ->(编译) class文件 -> Java虚拟机中运行
2.面向对象: 以人类正常思维开发和设计软件,开发程序开发方法:支撑大型的关系复杂系统的构建
3.多线程:支持多任务场景
4.分布式:支持网络应用
5.简单:比C++简单 指针,回收(内存泄露)Java中没有指针, 系统自动回收
变量和运算符
Java中的变量
什么是变量:指在内存中开辟的存储空间,用于存放在运算过程中用到的数据。
(大家住在G2,公寓需要开通一个房间给大家,提高大家居住)
(插卡游戏机中,破解版的坦克大战,魂斗罗可以无限设置多少条命,我们在游戏中改变的
哪一个数据就是变量,用于表示玩家的生命数)
如何声明变量
例:Int id=123; (int 是变量的类型 id是变量名 123是变量的赋值)
Java中规定在使用一个变量前,必须对该变量进行声明并初始化
声明就是给变量一个数据类型,初始化就是对变量赋值
方式:声明的同时初始化,先声明后初始化
变量是一个代词:指代的是内存中的数据
变量是可变化的量,改变的是该变量所指代的数据。
变量的命名:
可以由字母,数字,”_”和“$”组成。
不能以数字开头,区分大小写,不能使用java的关键字和保留字
可以使用中文命名但不建议使用。
建议:见名知意 驼峰命名法
Java中的8中基本数据类型
整数类型:
byte 1Byte
short 2Byte
int 4Byte(整数的默认类型)
long 8Byte
浮点数类型 float 4Byte
double 8Byte(浮点数的默认类型)
字符类型 char 2Byte 存储一个字符(英文,汉字...)
布尔类型 boolean 1Byte true(真) false(假)
基本数据类型之间的转换
1.自动类型转换(隐式转换):从小到大
2.强制类型转换 :
int num=(int) 5.21;
Double ->int 会造成精度的缺失,对数据产生影响。
Byte short char转为int (三种类型实际存储的数据都是整数)
整数直接量可以直接赋值给Byte short char(大->小 系统帮忙转了)
Byte short char三种类型参与运算时,先一律转成int再进行运算
Java中的运算符
除法(/)适用于两个整数,结果舍弃小数部分
取余(%) 适用于整数,char,浮点数:结果取决于除数的正负。
自增(++):使变量的值+1;自减(--):使变量的值-1;
注意:参与运算时,运算符写在变量前,变量后的效果不同
关系运算符:用于判断数据之间的大小关系:(>,<,>=,<=,==,!=)
关系运算的结果为boolean(true/false)
逻辑运算符: &&(与) ,||(或),!(非)
&&(与):多个条件同时满足。整个表达式为true
||(或):多个表达式中,只要有一个满足,整个表达式为true。
!(非):非真则假,非假则真。
短路问题
11&17 运算 二进制 (1-1为1 其余为0)
参与逻辑运算的表达式的结果都是布尔值。
特殊的运算符:+=,-=,*=,/=
三目运算表达式:(boolean)表达式?表达式1:表达式2
先计算(boolean)表达式,若为true,则整个表达式返回表达式1
若为false则整个表达式返回表达式2
移位运算符(了解)
<< 左移
>> 右移
2 << 3 == 16
2的 二进制表示 10 %2
16的 二进制表示 10000 %16
负数N(-35)转成二进制
先将35的二进制数求出 00100011
全部位安位取反 11000100
再加1:11000101
流程控制语句
分支结构:
if: if(逻辑表达式){ 语句块 } 如果逻辑表达式成立,则执行语句块代码
If( ){ }else{ } ; if(){ }else if(){ }
switch case:--break
If-else-if:相对灵活 ; switch case:结构更清晰
循环结构:for ,wihle,do-while
while:while( 表达式){ 语句块 } :先判断在执行
do{ 语句块}while(表达式):先执行一次,在判断
for(表达式1; 表达式2; 表达式3){ 循环体 } 一般用于固定次数的循环
表达式1:循环变量的初始化
表达式2:循环条件
表达式3:循环变量的改变
Break;跳出循环,使用continue跳过本次循环进入下次循环
or循环输出1 到100
while循环输出1-100
计算2000年1月1日到2008年1月1日相距多少天
输出1 到100的累加和
求100以内所有偶数的和
求整数1~100的累加值,但要求跳过所有个位为3的数
循环输入大于0的数字进行累加,直到输入的数字为0,就结束循环,并最后输出累加的结果
打印出?100~999之间的所有“水仙花数”。所谓“水仙花数”,是指一个3
位数,其各位数字立方和等于该数本身
输入一个整数N,判断该数是不是质数,如果是质数输出"N是一个质数",否
则输出"N不是质数"。提
示:除了1和它本身不能被任何数整除
求9的阶乘;9!=123456789?
猜数字游戏.
数组
什么是数组:
什么是数组:Java中用于存储数据的容器。
数组的声明和创建:引用数据类型的方式
数组的初始化:
1.int[] arr=new int[]{1,2,3,4,5};
2.int []arr=new int[5];
3.int[] arr={1,2,3,4,5};
数组元素的访问:
在JAVA中通过下标访问数组的元素,数组的下标从0开始,表示第一个元素
数组的属性:长度length,表示数组的长度
利用数组的属性length,遍历数组
for(int i=0; i<arr.length;i++){
Systen.out.println(arr[i])
}
数组的异常:当访问数组下标超过数组大小时,会报异常,数组下标越界
方法的定义及调用
微信红包小程序
public class WeiCat {
public static void main(String[] args) {
// TODO Auto-generated method stub
String wid="cl666";//微信号
String pwd="cl123456";//微信密码
String payID="888888";//支付密码
double balance=800;//红包零钱
double money=0;
String upay;
Scanner scan=new Scanner(System.in);
while(true){
System.out.println("微信号");
String uwid=scan.next();
System.out.println("请输入密码");
String upwd=scan.next();
if(uwid.equals(wid)&&upwd.equals(pwd)){
//登陆成功
break;
}else{
//登陆失败
System.out.println("请重新登陆");
}
}
System.out.println("1.发红包 2.转账 3.提现 4.充值");
int num=scan.nextInt();
switch(num){
case 1:
System.out.println("请输入红包金额");
money=scan.nextDouble();
if(money>balance){
System.out.println("红包零钱不足");
}else{
System.out.println("请输入支付密码");
upay=scan.next();
if(upay.equals(payID)){
System.out.println("红包发生成功");
balance-=money;
}else{
System.out.println("支付密码有误");
}
}
break;
case 2 :
break;
case 3:
break;
case 4:
break;
default:
System.out.println("选项无效");
}
}
}
什么是方法:完成某个特定功能的语句。
特定功能就是一段具有运算功能的代码
随着学习的深入,代码量会随之增多。之前都写在一个main方法中 ,如果代码量达到
几千行 甚至一万行的话 ,对于程序的可视化效果 与分析都非常不好,所以使用方法
将代码进行简化
生活案例:电饭煲 自动贩卖机 压汁机
特点:使用者无需了解工具具体的内部实现 只需了解工具的使用规则
方法的例子: System.out.print(); 方法的特点 都有小括号
Arrays.sort() Arrays.copyOf() 具有运算的功能
使用方法编程的优点:保证一个方法 只做一件事
银行:存钱( ) 取钱( ) 余额( )
操作( 存钱 取钱 余额)
减少代码的复用 ,便于程序的维护
方法的特点:方法的调用者无需知道方法的内部实现 只需了解方法需要的参数即可
方法的定义:[ 访问控制符 ] [ 修饰符 ] 返回值类型 方法名([参数类型 参数名]){ }
[ 访问控制符 ] [ 修饰符 ] :后续进行讲解
返回值类型:该方法运算结果的数据类型(Object ,基本数据类型,引用类型)
如果声明的返回值类型与实际返回的类型不同,会编译报错
方法名([参数类型 参数名]):统称参数列表
方法名:作为调用该方法的标识
参数:作为方法中运算时用到的数据,个数没有限制,若有参数,要声明参数类型
方法体:是一个语句块,执行特定的功能代码
return :返回值的关键字
方法的分类:
根据参数个数:
有参方法
无参方法
根据返回值类型
有返回值的方法
无返回值的方法
参数与返回值类型的多样化
1. 参数:3个 类型:String int int 返回值类型:boolean
在保存了多个学生姓名的数组中,指定查找区间,查找某个学生姓名并显示是否查找成功
public static boolean selectName(String str ,int start,int end ){
if(start<0){
start=0;
}
if(end>=names.length-1){
start=names.length-1;
}
for(int i=start ;start<=end;i++){
if(names[i].equals(str)){
return true;
}
}
return false;
}
2.参数:1个 类型:int[ ] 返回值:double/int
有5位学员参加了Java知识竞赛的决赛,输出决赛的平均成绩和最高成绩
//求平均成绩
public static double getAvg(int [] score){
int sum=0;
for(int i=0;i<score.length;i++){
sum+=score[i];
}
return sum/score.length;
}
//求最大值
public static double getMax(int [] score){
Arrays.sort(score);
return score[score.length-1];
}
3.参数:1个 类型:int[ ] 返回值:int[ ]
在保存多个学生成绩的数组中,将学生的成绩安装升序排序
public static int [] sortArray(int [] score){
Arrays.sort(score);
return score;
}
public static int [] sortArray1(int [] score){
int temp;
for(int i=0;i<score.length;i++){
for(int j=0;j<score.length;j++){
if(score[j]>score[j+1]){
temp=score[j];
score[j]=score[j+1];
score[j+1]=temp;
}
}
}
return score;
}
4.参数:0 类型:无 返回值:int
求1—100之间的整数和
public static int getSum(){
int sum=0;
for(int i=1;i<=100;i++){
sum+=i;
}
return sum;
}
5.参数:2个 类型:int 返回值:int
求两个整数区间的和
public static int getSum(int a,int b){
int sum=0;
for(int i=a;i<=b;i++){
sum+=i;
}
return sum;
}
6.参数:3个 类型:int 返回值:double
求三个整数的和
public static int getSum(int a1,int a2 ,int a3){
return a1+a2+a3;
}
7.参数:1个 类型:char[ ] 返回值:boolean
用户随机输入5个字符,判断是否为“回文”(例:abcba,12321)
public static boolean checkFlag(char[] c){
boolean flag=true;
for(int i=0;i<c.length;i++){
if(c[i]==c[c.length-1-i]){
flag=true;
}else{
flag=false;
return flag;
}
}
return flag;
}
8.参数:3个 类型:int 返回值:int
随机输入不相同的三个整数 比较出其中的最大值
public static int getMax(int a,int b,int c){
if(a>b&&a>c){
return a;
}else if(b>a&&b>c){
return b;
}else if(c>a&&c>b){
return c;
}
return 0;
}
9.参数:2个 类型:int 返回值 :int
求两个整数之间存在多少个奇数
public static int countNum(int a,int b){
int count=0;
for(int i=a;i<=b;i++){
if(i%2!=0){
count++;
}
}
return count;
}
10.参数:1个 类型:int 返回值 :boolean
随机输入一个年份 判断是否为闰年
public static boolean checkYear(int year){
if(year%4==0&&year%100!=0||year%400==0){
return true;
}
return false;
}
11.参数:1个 类型 :char[ ] 返回值:无
输入一行字符,分别统计出其中英文字母、数字和其它字符的个数
有一个方法被调用代码为int[] arrs = sort(new Student(12))
求该方法的声明代码
答案:public int[] sort(Student arr)
有一个方法被调用代码为String[][] strs = sort(15),该方法的声明代码为
答案:public String[][] sort(int n)
参数的传递:
参数传递的过程实际就是把实参的值传递给形参的过程
方法的调用
在同一个类中static修饰的方法可以直接通过方法名进行调用
在不同的类中 static修饰的方法 通过类名.方法名进行调用
非static修饰的方法 通过对象.方法名进行调用
方法的重载
在同一个类中 允许同时存在多个方法名相同的方法
规则:
方法名必须相同
参数列表不同
参数个数不同
参数类型不同
与返回值类型无关
总结和练习
总结练习: 猜字符游戏
1.设计数据结构---变量
2.设计程序结构—方法
3.设计实现----方法的实现
public class Guess {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scan=new Scanner(System.in);
String[] c=getChar();
// for(String c1:c){
// System.out.print(c1+" ");
// }
System.out.println("开始猜吧..");
String[] cs;
int count=0;
while(true){
System.out.println("请输入第1个字母");
String input1=scan.next();
System.out.println("请输入第2个字母");
String input2=scan.next();
System.out.println("请输入第3个字母");
String input3=scan.next();
System.out.println("请输入第4个字母");
String input4=scan.next();
System.out.println("请输入第5个字母");
String input5=scan.next();
cs=new String[]{input1,input2,input3,input4,input5};
int [] result=getResult(c,cs);
System.out.println("位置正确个数:"+result[0]);
System.out.println("字符正确个数:"+result[1]);
if(result[0]==5&&result[1]==5){
break;
}
count++;
}
System.out.println("您一共猜了"+count+"次");
}
public static String[] getChar(){
Random r=new Random();
int index;
String[] ch=new String[5];
String[] cs={"A","B","C","D","E","F","G","H","I","J",
"K","L","M","N","O","P","Q","R","S","T",
"U","V","W","X","Y","Z"
};
boolean[] flag=new boolean[cs.length];
for(int i=0;i<ch.length;i++){
do{
index=r.nextInt(cs.length);
}while(flag[index]);
ch[i]=cs[index];
flag[index]=true;
}
return ch;
}
public static int [] getResult(String[] xc ,String[] uc){
int [] result=new int[2];
for(int i=0;i<xc.length;i++){
for(int j=0;j<uc.length;j++){
if(xc[i].equals(uc[j])){
if(i==j){
result[0]++;//位置
}
result[1]++;//个数
}
}
}
return result;
}
}
面向对象
面向对象:是一种编程思想,是对人类思维进行归纳总结,在计算机中模拟现实世界的开发方法是以对象为核心,围绕对象进行操作
面向过程: 通常分析出解决问题需要的步骤,然后用方法把这些步骤实现,最后一次调用这些方法。缺乏对参数的封装。
面向过程主要考虑的是程序的流程和算法而数据只是在需要时插入到算法中。
为什么使用面向对象:
可以解决复杂的关系和逻辑
利用人类的思维进行编程
支持程序扩展,维护性更换
如何实现面向对象:了解类和对象
类:具有一类事物共同特征和行为的抽象。
鸟:- - - 就是抽象出来的对这类事务的描述 - - - 计算机中叫做 类(一种引用类型)
特征:翅膀 脚 眼睛 行为:飞 吃
抽象中可能发生的问题:
认知可能不准确 - - - 强调”共有的” 没有忽略次要特征(与业务相关的特征)
对象:类在现实生活中的实例
Java程序完成类的创建
创建类的对象
操作累的属性和方法
构造方法:
在创建对象时,通过构造方法完成对象的内存开辟和初始化
构造方法的特点:
在开发中如果没有编写构造方法,系统会提共一个默认的无参构造方法,
但是若定义了任何类型的构造方法,系统则不会提供默认构造器
构造方法可以重载
构造方法不可以有返回值
通过有参构造方法初始化属性
This关键字:表示当前对象的引用
使用情况:成员变量(属性)与局部变量重名
在一个构造器中 调用其他重载的构造器
需要返回当前对象的引用
public class Car{
int num=0;
public Car getCar(){
num++;
return this;
}
public Car getCar(){
num++;
return new Car();
}
public void sayNum(){
System.out.println(num);
}
}
对象的内存模型
栈:保存基本数据类型的局部变量和引用类型的引用。
特点:存取速率块,效率高
堆:new 出来的对象都保存在堆中
特点:存储对内存空间要求较大的变量
匿名对象 (new Person().sayHi();) 该对象只使用一次
垃圾回收器:
Java的垃圾回收机制是自动的,实际上是JVM内部运行的一个优先级比较低的后台线程
垃圾回收机制仅仅作用于堆内存中,与栈无关
垃圾:堆中的内容不存在任何引用指向它
内存泄露:不再使用的内存没有被及时的回收
New Xd(); - -匿名对象
### 扑克游戏 :
public class Poke {
private String size;//牌号
private String color;//花色
private int code;//大小
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "size=" + size + ", color=" + color + ", code=" + code;
}
}
public class Pokes {
private String[] colors={"红桃","黑桃","方片","梅花"};
private String [] sizes={"2","3","4","5","6","7","8","9","10","J","Q","K","A"};
//生成52张扑克
public Poke[] getPoke(){
int n=0;
Poke[] p=new Poke[52];
for(int i=0;i<colors.length;i++){
for(int j=0;j<sizes.length;j++){
Poke poke=new Poke();
poke.setColor(colors[i]);
poke.setSize(sizes[j]);
poke.setCode(j);
p[n]=poke;
n++;
}
}
return p;
}
}
package entity;
import java.util.Random;
import java.util.Scanner;
public class Start {
public static void main(String[] args) {
/*
* 随机发牌
* 庄家 玩家
* 1. 各发一张牌
* 庄家底牌显示 提示玩家 是否看底牌 不看得分翻倍
* 2.发第二张牌
* 第二张牌显示 提示是否看底牌 不看得分翻倍
* 3.发第三张牌
* 直接翻牌
* 发牌结束 双方比较大小
*/
// TODO Auto-generated method stub
Pokes ps=new Pokes();
Poke[] p=ps.getPoke();
int score=1000;
System.out.println("欢迎来到 炸金花 PK大赛");
while(score>0){
boolean[] flag=new boolean [p.length];
int sz;
int sx;
Scanner scan=new Scanner(System.in);
int[] xscore=new int[3];
System.out.println("第一轮发牌");
Poke pz1=getPoke(p,flag);
System.out.println("庄家: 底牌");
Poke px1=getPoke(p,flag);
System.out.println("玩家: 底牌");
System.out.println("玩家是否看牌:1.是 2.不是");
int num=scan.nextInt();
if(num==1){
System.out.println("玩家:"+px1.getColor()+px1.getSize());
}else{
System.out.println("玩家未看底牌");
}
System.out.println("请下注");
xscore[0]=scan.nextInt();
System.out.println("玩家下注:"+xscore[0]);
if(num==2){
xscore[0]*=2;
}
System.out.println("第二轮发牌");
Poke pz2=getPoke(p,flag);
System.out.println("庄家:"+"底牌"+" "+pz2.getColor()+pz2.getSize());
Poke px2=getPoke(p,flag);
if(num!=1){
System.out.println("玩家:"+"底牌"+" "+px2.getColor()+px2.getSize());
System.out.println("玩家家是否看牌:1.是 2.不是");
num=scan.nextInt();
if(num==1){
System.out.println("玩家:"+px1.getColor()+px1.getSize()+" "+px2.getColor()+px2.getSize());
}else{
System.out.println("玩家未看底牌");
}
}else{
System.out.println("玩家:"+px1.getColor()+px1.getSize()+" "+px2.getColor()+px2.getSize());
}
System.out.println("请下注");
xscore[1]=scan.nextInt();
System.out.println("玩家下注:"+xscore[1]);
if(num==2){
xscore[1]*=2;
}
System.out.println("第三轮发牌");
Poke pz3=getPoke(p,flag);
System.out.println("庄家:"+"底牌"+" "+pz2.getColor()+pz2.getSize()+" "+pz3.getColor()+pz3.getSize());
Poke px3=getPoke(p,flag);
if(num!=1){
System.out.println("玩家:"+"底牌"+" "+px2.getColor()+px2.getSize()+" "+px3.getColor()+px3.getSize());
System.out.println("玩家家是否看牌:1.是 2.不是");
num=scan.nextInt();
if(num==1){
System.out.println("玩家:"+px1.getColor()+px1.getSize()+" "+px2.getColor()+px2.getSize()+" "+px3.getColor()+px3.getSize());
}else{
System.out.println("玩家未看底牌");
}
}else{
System.out.println("玩家:"+px1.getColor()+px1.getSize()+" "+px2.getColor()+px2.getSize()+" "+px3.getColor()+px3.getSize());
}
System.out.println("请下注");
xscore[2]=scan.nextInt();
System.out.println("玩家下注:"+xscore[2]);
if(num==2){
xscore[2]*=2;
}
Poke[] pokez={pz1,pz2,pz3};
Poke[] pokex={px1,px2,px3};
System.out.println("请双方亮牌");
System.out.println("庄家:"+pz1.getColor()+pz1.getSize()+" "+pz2.getColor()+pz2.getSize()+" "+pz3.getColor()+pz3.getSize());
System.out.println("玩家:"+px1.getColor()+px1.getSize()+" "+px2.getColor()+px2.getSize()+" "+px3.getColor()+px3.getSize());
sz=setScore(getTpye(pokez));
sx=setScore(getTpye(pokex));
String result=show(sz,sx,pokez,pokex);
if("玩家赢".equals(result)){
score+=xscore[0]+xscore[1]+xscore[2];
System.out.println("本轮玩家赢");
}else{
score-=xscore[0]+xscore[1]+xscore[2];
System.out.println("本轮庄家赢");
}
System.out.println("玩家积分"+score);
}
}
public static Poke getPoke(Poke[] p,boolean[] flag){
Random r=new Random();
int index;
do{
index=r.nextInt(p.length);
}while(flag[index]);
flag[index]=true;
return p[index];
}
//比较牌面大小
public static String getTpye(Poke[] pz){
Poke p;
for(int i=1;i<pz.length;i++){
for(int j=0;j<pz.length-i;j++){
if(pz[j].getCode()>pz[j+1].getCode()){
p=pz[j];
pz[j]=pz[j+1];
pz[j+1]=p;
}
}
}
if(pz[0].getSize().equals(pz[1].getSize())&&pz[1].getSize().equals(pz[2].getSize())){
return "三条";
}
if(pz[0].getSize().equals(pz[1].getSize())||pz[1].getSize().equals(pz[2].getSize())||pz[0].getSize().equals(pz[2].getSize())){
return "一对";
}
if(!pz[0].getSize().equals(pz[1].getSize())&&!pz[1].getSize().equals(pz[2].getSize())&&!pz[0].getSize().equals(pz[2].getSize())
&&(pz[0].getCode()+1!=pz[1].getCode()||pz[1].getCode()+1!=pz[2].getCode())){
return "单牌";
}
if(pz[0].getCode()+1==pz[1].getCode()&&pz[1].getCode()+1==pz[2].getCode()
&&pz[0].getColor().equals(pz[1].getColor())&&pz[1].getColor().equals(pz[2].getColor())){
return "同花顺";
}
if(pz[0].getCode()+1==pz[1].getCode()&&pz[1].getCode()+1==pz[2].getCode()){
return "顺子";
}
if(pz[0].getColor().equals(pz[1].getColor())&&pz[1].getColor().equals(pz[2].getColor())){
return "同花";
}
return null;
}
//比较输赢
public static String show(int pz,int px,Poke[] pz1,Poke[] px1){
if(pz==px){
if(pz1[2].getCode()>px1[2].getCode()){
return "庄家赢";
}else{
return "玩家赢";
}
}
if(pz>px){
return "庄家赢";
}else{
return "玩家赢";
}
}
//牌面积分
public static int setScore(String type){
int score=0;
if(type.equals("同花顺")){
score=6;
}
if(type.equals("三条")){
score=5;
}
if(type.equals("同花")){
score=4;
}
if(type.equals("顺子")){
score=3;
}
if(type.equals("一对")){
score=2;
}
if(type.equals("单牌")){
score=1;
}
return score;
}
}
面向对象高级特性
为什么使用继承:
不同的类之间存在一些相同的属性和方法
所以将类中相同的属性和方法提取到公共类中
Student | Teather |
---|---|
name : String | name : String |
age : int | age : int |
sid : int | tyear : int |
eat(); | eat(); |
exam(); | checkPaper();; |
什么是继承:Java中通过extends 关键字让一个类继承另一个类,被继承的类叫父类(超类,基类),新的类叫子类(派生类)。
子类可以拥有父类所有的属性和方法
继承的语法和规则:
语法: public class Student extends Person{ 属性 方法 }
继承的优点:代码的复用。
例:创建一个建设银行的ATM类 ,实现密码校验方法,取款方法,手机充值方法
创建一个工商银行的ATM类,实现密码校验方法,取款方法,转账方法
发现:其实密码校验以及取款是每个银行的ATM都存在的功能,在编码时写了重复代码,这时可以创建ATM类,让它实现校验密码和取款的方法。而其它的ATM类继承该类,就可以使用这些方法了。
Java中是单一继承,一个类只能有一个父类
子类实例化的过程:
子类实例化会先实例化其父类,父类构造器调用完毕,才执行子类构造器
子类继承父类,在子类的构造方法的第一句一定会调用父类的构造方法
如果父类没有明确的构造方法,父类使用的是默认构造器。
子类在继承父类时,在子类构造方法中会默认调用父类的默认构造器 super()可以不写
子类在自己的构造器中使用super关键字调用父类的构造器 super(参数1,参数2,...)
如果子类调用了父类的无参构造器 而父类中没有无参构造器则会编译报错
Super和this:
Super(); 指向父类的引用 调用父类的构造器,只能出现在子类的构造器中,
且必须在第一行super()中有无参数,决定了调用哪个构造器。
在同一个构造器中,不能同时出现 super和this
思考以下代码的运行结果
publics class Car {
private int site = 4; //座位数
Car(){
System.out.println ("载客量是"+site+"人);
}
public void setSite(int site){
this.site = site;
}
void print(){
System.out.print("载客量是"+site+"人");
}
}
class Bus extends Car {
Bus(int site){
setSite(site);
}
}
public static void main(String[] args) {
Bus bus = new Bus(20);
bus.print();
}
封装: 对类中的属性和方法规定访问权限,保护类中数据的安全
将类中的信息(属性和方法)隐藏起来,不允许外部程序之间访问,而是通过该类
提供的方法进行访问
活中的例子:到饭馆吃饭,你只需要跟服务员讲你要吃什么饭菜服务员就会跟后台厨房的厨师说明一下
等待一段时间后,饭菜就被服务员直接递送到你面前,作为客户的你是不知道也无需知道饭菜的具体做法,
后台厨房的厨师及做饭菜的过程就是被封装的细节,而服务员则是公开暴露的访问路径,
你只能通过服务员点餐然后获得饭菜,而不能直接去到后台厨房要求厨师如何做饭菜;
类中存在属性name ,调用类随意对属性进行赋值 ,不会符合规范 没有意义。
这是由于调用类可以直接访问到类中的属性
访问权限:用来控制类的成员和类的使用范围
private:私有地
default:默认地
protected:受保护的
public:公共的
public 和 默认 可以修饰类
get方法和set方法访问类中的属性
多态:子类和父类之间,不同的子类之间对于同一行为,有不同的实现方式
例:王者荣耀中的英雄都有技能 但不同的英雄技能不同
每个形状都有面积 但不同的形状面积不同
体现:方法的重写/override
方法的签名相同(方法名,参数列表) ,方法体不同。
例:定义形状类 定义求面积 周长的方法
定义圆形类 声明属性半径 继承 形状类
由于不同形状求面积方法不同 需要重写父类的原始方法
class Shape{
double c;
public double area();
}
class Square extends Shape{
public Square(double c){
this.c = c;
}
public double area(){
return 0.0625*c*c;
}
}
class Circle extends Shape{
public Circle(double c){
this.c = c;
}
public double area(){
return 0.0796*c*c;
}
}
重写方法被调用时,看对象类型。子类对象的重写方法被调用时,引用类型无论是父类还是子类,运行的都是子类重写后的版本。
方法重写后的调用原理
code..
可以通过super.方法名 在子类重写方法中调用父类方法。
重写方法的注意事项:
1.方法名相同 ,参数列表相同
2.子类方法的返回值类型void等于父类,基本类型等于父类
3.子类方法抛出的异常小于或等于父类
4.子类方法的访问权限大于或等于父类
重载和重写的区别:
重写:遵循“运行期”的绑定,根据对象类型进行调用
重载:遵循“编译器”的绑定,根据参数列表不同进行调用
以下代码中 那些是方法的重载,那些是方法的重写 以及运行结果
public class OverrideOverloadDemo {
public static void main(String[] args){
Goo g = new Goo();
Eoo e = new Eoo();
g.show(e);
Foo f =new Foo();
g.show(f);
Eoo e1 = new Foo();
g.show(e1);
Foo f1 = new Foo();
g.show(f1);
}
}
//overload
class Goo{
void show(Eoo e){
System.out.println("父类参数");
e.show();
}
void show(Foo f){
System.out.println("子类参数");
f.show();
}
}
class Eoo{
void show(){
System.out.println("父类show方法");
}
}
class Foo extends Eoo{
void show(){
System.out.println("子类show方法");
}
}
引用数据类型的转换:
“麻烦你,小王。帮我把那个东西拿过来好吗”
在生活中,你肯定用过这个词--东西。
小王:“你要让我帮你拿那个水杯吗?”
你要的是水杯类的对象。而东西是水杯的父类。通常东西类没有实例对象,但我们有时需要东西(父类)的引用指向它的子类实例。
父子类之间的转换:
上溯造型(向上造成):子类对象- - > 父类对象,造成子类特有的,扩展的属性和方法失效,只能有父类继承的属性和方法。
优点:有利于程序的维护和扩展。
public class Master {
private String name = "";// 主人名字
private int money = 0; // 元宝数
/**
* 有参构造方法。
* @param name 主人名字
* @param money 元宝数
*/
public Master(String name, int money) {
this.name = name;
this.money = money;
}
public void setName(String name) {
this.name = name;
}
public void setMoney(int money) {
this.money = money;
}
public int getMoney() {
return money;
}
public String getName() {
return name;
}
/**
* 主人给Dog喂食。
*/
public void feed(Dog dog) {
dog.eat();
}
}
public class Pet {
private String name = "无名氏";// 昵称
private int health = 100;// 健康值
private int love = 0;// 亲密度
/**
* 方法eat(),负责宠物吃饭功能。
*/
public void eat();
/**
* 有参构造方法。
* @param name 昵称
*/
public Pet(){
}
public Pet(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public void setHealth(int health) {
this.health = health;
}
public void setLove(int love) {
this.love = love;
}
public String getName() {
return name;
}
public int getHealth() {
return health;
}
public int getLove() {
return love;
}
}
public class Dog extends Pet {
private String strain;// 品种
/**
* 有参构造方法。
* @param name 昵称
* @param strain 品种
*/
public Dog(String name, String strain) {
super(name);
this.strain = strain;
}
public String getStrain() {
return strain;
}
/**
* 重写吃食方法。
*/
public void eat() {
if(getHealth()>=100){
System.out.println("狗狗"+this.getName() +"吃饱了,不需要喂食了!");
}else{
this.setHealth(this.getHealth()+3);
System.out.println("狗狗"+this.getName() + "吃饱啦!健康值增加3。");
}
}
}
如果再领养新种类XXX的宠物,就需要给XXX喂食,怎么办?
添加XXX宠物类,继承Pet类,实现吃食方法
修改Master类,添加给XXX宠物喂食的方法
可以发现随着程序的不断扩展,需要对源程序进行不断的修改,这不符合程序的设计原则
频繁修改代码,程序的可扩展性、可维护性变得很差
使用多态优化设计
修改Master 类的eat()方法 将参数 改为Pet类型
实现一个方法可以 对所有宠物喂食
public void feed(Pet pet) {//父类的引用指向子类的对象
pet.eat();
}
调用Master类的喂食方法时可以传入其子类对象 从而调用不同子类的喂食方法
下溯造成:父类-- >子类 直接强转会报类型转换错误,要求父类对象必须是由子类对象向上转换过的,才可以向下转换
类型转换这部分在讲解时,讲解时学生能够知道有这样一种写法。
但是大多数学生不理解为什么要这么去写。所有需要设置一个案例,使学生能够理解向上造型的用途。
例:生产汽车根据不同的的参数 返回不同类型的汽车类 但方法的返回值是 汽车的父类
抽象类 abstract:该类不需要创建对象,提出了一个概念,其中的方法有子类实现。
特点:抽象类不能实例化
抽象类中可以有普通方法,可以有抽象方法
向子类提供父类的定义,抽象类就是给其他类继承的
子类继承抽象类:普通类必须实现抽象方法,抽象子类不实现
抽象类作用:为子类提供一个公共的类型;
抽象类的应用——模板设计模式
例如,现在有三类事物:
(1)机器人:充电,工作;
(2)人:吃饭,工作,睡觉;
(3)猪:进食,睡觉。
现要求实现一个程序,可以实现三种不同事物的行为。
所有的子类如果要想正常的完成操作,必须按照指定的方法进行覆写才可以
而这个时候抽象类所起的功能就是一个类定义模板的功能。
定义一个Employee抽象基类
公司有以下几种员工:
开发人员:工资计算方式,每月固定工资
销售人员:底薪+提成
小时工:按工作时间付工资,每小时30元
创建不同类型的3名员工对象,计算他们应付的月工资之和
public abstract class Employee {
private String name;
public Employee(String name)
{
this.name = "@" + name + "@" ;
}
protected abstract int paySalary();
}
//开发人员
public class Developer extends Employee{
private int salary;
public Developer(String name, int salary)
{
super(name);
this.salary = salary;
}
@Override//方法重写注解
protected int paySalary() {
return salary;
}
}
//销售人员
public class SaleMan extends Employee{
private int salary;
private int comm;//提成
public SaleMan(String name, int salary, int comm)
{
super(name);
this.salary = salary;
this.comm = comm;
}
@Override
protected int paySalary() {
return salary + comm;
}
}
//小时工
public class HourlyWorker extends Employee{
private int hours;//这个月工作了多少小时
public HourlyWorker(String name, int hours)
{
super(name);
this.hours = hours;
}
@Override
protected int paySalary() {
return 30*hours;
}
}
public class Main {
public static void main(String[] args) {
Employee[] employees = new Employee[3];
employees[0] = new Developer("张三",5000);
employees[1] = new SaleMan("李四", 2000, 500);
employees[2] = new HourlyWorker("冯六",200);
//计算总工资
int total = 0;
for(int i = 0; i < employees.length; i++)
{
total += employees[i].paySalary();
}
System.out.println("总共需要支付" + total);
}
}
关键字 final
修饰类: 该类不能被继承
修饰属性和变量:赋值后不允许修改数值,地址不能改变
修饰方法:方法不能被重写
final练习演示
思考一个有趣的现象:
byte b1=1;
byte b2=3;
byte b3=b1+b2;//当程序执行到这一行的时候会出错,因为b1、b2可以自动转换成Int类型的变量,运算时java虚拟机对它进行了转换,结果导致把一个int赋值给byte-----出错
如果对b1 b2加上final就不会出错
final byte b1=1;
final byte b2=3;
关键字 abstract 和 final 不能同时使用
接口 Interface:几类完全不同的事物,拥有同样的行为,这种行为定义在接口中。
接口是一种标准,一种协议,一种规范
USB接口本身没有实现任何功能
USB接口规定了数据传输的要求
USB接口可以被多种USB设备实现
接口的特点:
接口不是类
接口中定义的只能是抽象方法,无论是否书写abstract关键字
接口中属性,必须是final修饰—常量 ,无论是否写了final
一个类可以实现多个接口, 接口可以继承接口(多继承)
实现接口的演示
public interface UsbInterface {
//USB接口提供服务。
void service();}
public class UDisk implements UsbInterface {
public void service() {
System.out.println("连接USB口,开始传输数据。");
} }
接口在多态中的体现:
1.继承或实现
2.重写
3.父类(接口)的声明指向子类的对象
接口和抽象类的区别:
一个是类,一个是接口
抽象类可以有抽象方法,也可以有普通方法,接口中都是抽象方法
抽象类中可以有普通的属性,接口中是常量
接口使用练习
public class UnionPayTest {
public static void main(String[] args) {
ICBCImpl card1 = new ICBCImpl(10000,"qwer12");
Scanner scan = new Scanner(System.in);
System.out.println("请输入密码:");
if(card1.checkPwd(scan.next())){
System.out.println("请输入金额:");
if(card1.drawMoney(scan.nextDouble())){
System.out.println("所剩金额:"+card1.getBalance());
}else{
System.out.println("金额不足");
}
}else{
System.out.println("密码错误");
}
}
}
interface UnionPay{
public double getBalance();//查看余额
public boolean checkPwd(String input);//检查密码
public boolean drawMoney(double number);//取钱
}
interface ICBC extends UnionPay{
public void payOnline(double number);//在线支付
}
interface ABC extends UnionPay{
public boolean payTelBill(String phoneNum,double sum);//支付电话费
}
class ICBCImpl implements ICBC{
private double money;//账户余额
private String pwd;//账户密码
public ICBCImpl(double money,String pwd){
this.money = money;
this.pwd = pwd;
}
public double getBalance(){
return money;
}
public boolean checkPwd(String input){
if(pwd.equals(input)){
return true;
}else{
return false;
}
}
public boolean drawMoney(double number){
if(money-number>0){
money-=number;
return true;
}else{
return false;
}
}
public void payOnline(double number){
if(money>=number){
money-=number;
}
}
}
class ABCImpl implements ABC{
private double money;
private String pwd;
public ABCImpl(double money,String pwd){
this.money = money;
this.pwd = pwd;
}
public double getBalance(){
return money;
}
public boolean checkPwd(String input){
if(pwd.equals(input)){
return true;
}
return false;
}
public boolean drawMoney(double number){
if(money-number>-2000){
money-=number;
return true;
}else{
return false;
}
}
public boolean payTelBill(String phoneNum,double sum){
if(phoneNum.length()==11 && money-sum>-2000){
money-=sum;
return true;
}else{
return false;
}
}
}
静态static :
类和对象的关系,类是对象的模板,类中有属性和方法
Static修饰属性:所有对象共享该属性
Static修饰方法:所有对象共享该方法
被static修饰的属性和方法属于类,而不属于某个对象
静态方法中不能直接使用非静态属性和方法,只能调用其他的静态属性和方法
非静态方法可以直接调用普通资源和静态资源
static可以修饰的元素和使用特点
static 可以修饰 属性 方法 和 代码块
static修饰属性 :静态变量
所有对象共享 在类被载入时创建,只要类存在,static变量就存在
通过类名.属性名 / 对象.属性名 进行访问
static修饰方法:静态方法
不需要实例化对象 可以直接通过类名.方法名 访问
实例化对象后 可以 对象.方法名 访问
注意事项:
静态方法只能直接访问静态变量 不能直接访问成员变量
静态方法中不能使用super和this关键字
静态方法不能被覆盖(重写)
static修饰块:静态块
有static修饰的语句块 不包含任何方法体的代码块
当类被加载时 静态块被执行 并且只执行一次
常用于类属性的初始化
变量的作用域:
类变量:
用static修饰的成员变量,它们在类被载入时创建,只要类存在,static变量就存在
实例变量:
类体中声明的成员变量,即非static的属性,创建对象后存在
局部变量:
方法体中声明的变量,方法中的参数,或代码块中声明的变量,都是局部变量。局部变量只在方法调用的过程中有效,方法调用结束后失效
单例模式:在系统中该类只有一个实例化对象
在系统中某些类只需要一个对象就可以完成所有操作,会将类设计为单例模式以节省系统的开销
分为:饿汉模式 ,懒汉模式
Java的异常处理机制
是Java程序在编译或运行期间,发生的不可预期的意外,造成程序不能继续执行的情况
Java中的异常是被管理起来的,当程序发生异常,会创建出一个异常的对象
Throwable 所有异常的父类
Error 错误:天灾 人力不可抗拒 计算机硬件的问题,比如:硬盘坏了,内存掉电
java.lang.Exception 异常: 人祸 主要是因为程序开发者不严谨造成的问题,可以通过代码来修补和解决
检查性异常(编译)
强制要求在代码中处理异常
运行时异常(运行) java.lang.RuntimeException 非检查性异常
不强制在代码中处理异常
java.lang.ArrayIndexOutOfBoundsException 数组下标越界异常
IndexOutOfBoundsException 下标越界异常
java.lang.ArithmeticException 除数为0异常 (整数)
浮点数: 6.0 / 0 Infinity 无穷大
NaN 非数 Not a Number
java.lang.NullPointerException 空指针异常 (重点)
调用了null值的属性或方法 (null值没有任何属性和方法)
if(o != null){
o.toString();
}else{
..
}
java.lang.ClassCastException 引用数据类型类型转换异常
父类向子类转换时发生的异常(下溯造型时发生)
b instanceof B true 变量b是B类的一个对象
flase 变量b不是B类的一个对象
if(o instanceof B){
B b = (B)o;
}else{
..
}
异常的处理
1.上报/抛出
throw 人工制造异常
throws 表示某个方法向上抛出异常
面试:throw和throws的区别
2.捕获
try{
尝试执行代码
}catch(Exception e){
发生异常时捕获,执行此处
}finally{
无论如何都会执行
}
final和finally的区别?
final: 最终关键字
修饰类:不能被继承
修改方法:不能被重写
修改属性:常量
finally:异常捕获最终块:finally中的代码在try
包的概念:
什么是包
包的作用: 例 window文件系统 使用文件夹可以解决文件同名问题
使文档分门别类易于查找
包的命名方式:组织的域名反写
Java源文件与包的位置关系
将一个正整数分解质因数。例如:输入90,打印出90=233*5。
提示:对n进行分解质因数,应先找到一个最小的质数k,然后按下述步骤完成:
(1)如果这个质数恰等于n,则说明分解质因数的过程已经结束,打印出即可。
(2)如果n>k,但n能被k整除,则应打印出k的值,并用n除以k的商,作为新的正整数你n,重复执行第一步。
(3)如果n不能被k整除,则用k+1作为k的值,重复执行第一步
网友评论