├── Experiments ├── Cover.doc ├── KMeans_Set.txt ├── KMeans_Set2.txt ├── LR_ex0.txt ├── LR_ex1.txt ├── Questions.md ├── Questions_En.md ├── score.csv ├── wz1.png ├── wz2.png └── wz3.png ├── ch1.md ├── ch10.md ├── ch12.md ├── ch2.md ├── ch3.md ├── ch4.md ├── ch5.md ├── ch6.md ├── ch6_1.md ├── ch6_2.md ├── ch6_3.md ├── ch6_4.md ├── ch6_5.md ├── ch6_6.md ├── ch7.md ├── ch8.md ├── ch9.md └── fig ├── CDevPro.png ├── DBMS.png ├── DBMS2.png ├── ErrException.png ├── ErrException2.png ├── Error.png ├── ExceptionLayers.jpg ├── JDBC.png ├── JDBC2.png ├── JDBC3.png ├── JDBC4.png ├── JDBC5.png ├── JDBCAPI.png ├── Java-Mindmap ├── 4120002-4e4e2e7eaf3edea9.png ├── 4120002-4f8abdf9fa7ef630.png ├── 4120002-5989238d90b80c55.png ├── 4120002-5aed0e7d50180e47.png ├── 4120002-74dc7e59ddffda64.png ├── 4120002-764c12e8c74ab0dd.png ├── 4120002-7c2effe451a1bb9d.png ├── 4120002-7e4a2b32bca3882e.png ├── 4120002-8ed65d3657480ed0.png ├── 4120002-9120c6b8755abbcc.png ├── 4120002-9ac51deef1e7516d.png ├── 4120002-a0d0a03f1a1e1680.png ├── 4120002-a18a40fd0180afaa.png ├── 4120002-af9d74c2bfee9385.png ├── 4120002-b03fb6e32e6d7ebb.png ├── 4120002-bdb51e206ee9ca0d.png ├── 4120002-be47d789929ec252.png ├── 4120002-d0d8cda0cc9ca07c.png ├── 4120002-d105e32dea0dc8f9.png ├── 4120002-d753ccedc0c8af92.png ├── 4120002-d800586dfc967291.png ├── 4120002-e63eb183f6f860cf.png ├── 4120002-e8a41a869911f730.png ├── 4120002-ee23f25321b04d79.png ├── 4120002-f506cbdca8593918.png ├── 4120002-f6fefc4f54458850.png ├── 4120002-f8b7cdd3e8abf3e8.png ├── 4120002-fe108c58f2fee95f.png └── 4120002-febc1570c2425cf0.png ├── Java.png ├── JavaDataType.png ├── JavaDevPro.png ├── JavaRun.png ├── Javac.png ├── JvmSpec7.png ├── LearningJAVA.png ├── SearchExample.png ├── classBufferStream.png ├── classBufferStreamChain.png ├── classError.png ├── classFilter.png ├── classInput.png ├── classInputChain.png ├── classNumber.png ├── classOutput.png ├── classOutputChain.png ├── classReader.png ├── classWriter.png ├── classright.png ├── fileio.png ├── flowsample1.png ├── flowsample2.png ├── flowsample3.png ├── indonesian_map.jpg ├── iolevel.png ├── iostream.png ├── iostreaminput.png ├── iostreamoutput.png ├── james_gosling_java.jpg ├── java2JDK.gif ├── object-class.jpg ├── operator.png ├── packagedir.png ├── sortsample.png ├── sortsample2.png ├── swing.png ├── swing2.png ├── swing3.png ├── swing4.png ├── swingevents.png ├── swingevents2.png ├── swingjframe.png ├── swingjframe2.png ├── swingmvc.png ├── thread.png ├── thread2.png └── thread3.png /Experiments/Cover.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/Experiments/Cover.doc -------------------------------------------------------------------------------- /Experiments/KMeans_Set.txt: -------------------------------------------------------------------------------- 1 | 1.658985 4.285136 2 | -3.453687 3.424321 3 | 4.838138 -1.151539 4 | -5.379713 -3.362104 5 | 0.972564 2.924086 6 | -3.567919 1.531611 7 | 0.450614 -3.302219 8 | -3.487105 -1.724432 9 | 2.668759 1.594842 10 | -3.156485 3.191137 11 | 3.165506 -3.999838 12 | -2.786837 -3.099354 13 | 4.208187 2.984927 14 | -2.123337 2.943366 15 | 0.704199 -0.479481 16 | -0.392370 -3.963704 17 | 2.831667 1.574018 18 | -0.790153 3.343144 19 | 2.943496 -3.357075 20 | -3.195883 -2.283926 21 | 2.336445 2.875106 22 | -1.786345 2.554248 23 | 2.190101 -1.906020 24 | -3.403367 -2.778288 25 | 1.778124 3.880832 26 | -1.688346 2.230267 27 | 2.592976 -2.054368 28 | -4.007257 -3.207066 29 | 2.257734 3.387564 30 | -2.679011 0.785119 31 | 0.939512 -4.023563 32 | -3.674424 -2.261084 33 | 2.046259 2.735279 34 | -3.189470 1.780269 35 | 4.372646 -0.822248 36 | -2.579316 -3.497576 37 | 1.889034 5.190400 38 | -0.798747 2.185588 39 | 2.836520 -2.658556 40 | -3.837877 -3.253815 41 | 2.096701 3.886007 42 | -2.709034 2.923887 43 | 3.367037 -3.184789 44 | -2.121479 -4.232586 45 | 2.329546 3.179764 46 | -3.284816 3.273099 47 | 3.091414 -3.815232 48 | -3.762093 -2.432191 49 | 3.542056 2.778832 50 | -1.736822 4.241041 51 | 2.127073 -2.983680 52 | -4.323818 -3.938116 53 | 3.792121 5.135768 54 | -4.786473 3.358547 55 | 2.624081 -3.260715 56 | -4.009299 -2.978115 57 | 2.493525 1.963710 58 | -2.513661 2.642162 59 | 1.864375 -3.176309 60 | -3.171184 -3.572452 61 | 2.894220 2.489128 62 | -2.562539 2.884438 63 | 3.491078 -3.947487 64 | -2.565729 -2.012114 65 | 3.332948 3.983102 66 | -1.616805 3.573188 67 | 2.280615 -2.559444 68 | -2.651229 -3.103198 69 | 2.321395 3.154987 70 | -1.685703 2.939697 71 | 3.031012 -3.620252 72 | -4.599622 -2.185829 73 | 4.196223 1.126677 74 | -2.133863 3.093686 75 | 4.668892 -2.562705 76 | -2.793241 -2.149706 77 | 2.884105 3.043438 78 | -2.967647 2.848696 79 | 4.479332 -1.764772 80 | -4.905566 -2.911070 81 | -------------------------------------------------------------------------------- /Experiments/KMeans_Set2.txt: -------------------------------------------------------------------------------- 1 | 3.275154 2.957587 2 | -3.344465 2.603513 3 | 0.355083 -3.376585 4 | 1.852435 3.547351 5 | -2.078973 2.552013 6 | -0.993756 -0.884433 7 | 2.682252 4.007573 8 | -3.087776 2.878713 9 | -1.565978 -1.256985 10 | 2.441611 0.444826 11 | -0.659487 3.111284 12 | -0.459601 -2.618005 13 | 2.177680 2.387793 14 | -2.920969 2.917485 15 | -0.028814 -4.168078 16 | 3.625746 2.119041 17 | -3.912363 1.325108 18 | -0.551694 -2.814223 19 | 2.855808 3.483301 20 | -3.594448 2.856651 21 | 0.421993 -2.372646 22 | 1.650821 3.407572 23 | -2.082902 3.384412 24 | -0.718809 -2.492514 25 | 4.513623 3.841029 26 | -4.822011 4.607049 27 | -0.656297 -1.449872 28 | 1.919901 4.439368 29 | -3.287749 3.918836 30 | -1.576936 -2.977622 31 | 3.598143 1.975970 32 | -3.977329 4.900932 33 | -1.791080 -2.184517 34 | 3.914654 3.559303 35 | -1.910108 4.166946 36 | -1.226597 -3.317889 37 | 1.148946 3.345138 38 | -2.113864 3.548172 39 | 0.845762 -3.589788 40 | 2.629062 3.535831 41 | -1.640717 2.990517 42 | -1.881012 -2.485405 43 | 4.606999 3.510312 44 | -4.366462 4.023316 45 | 0.765015 -3.001270 46 | 3.121904 2.173988 47 | -4.025139 4.652310 48 | -0.559558 -3.840539 49 | 4.376754 4.863579 50 | -1.874308 4.032237 51 | -0.089337 -3.026809 52 | 3.997787 2.518662 53 | -3.082978 2.884822 54 | 0.845235 -3.454465 55 | 1.327224 3.358778 56 | -2.889949 3.596178 57 | -0.966018 -2.839827 58 | 2.960769 3.079555 59 | -3.275518 1.577068 60 | 0.639276 -3.412840 61 | -------------------------------------------------------------------------------- /Experiments/LR_ex0.txt: -------------------------------------------------------------------------------- 1 | 1.000000 0.067732 3.176513 2 | 1.000000 0.427810 3.816464 3 | 1.000000 0.995731 4.550095 4 | 1.000000 0.738336 4.256571 5 | 1.000000 0.981083 4.560815 6 | 1.000000 0.526171 3.929515 7 | 1.000000 0.378887 3.526170 8 | 1.000000 0.033859 3.156393 9 | 1.000000 0.132791 3.110301 10 | 1.000000 0.138306 3.149813 11 | 1.000000 0.247809 3.476346 12 | 1.000000 0.648270 4.119688 13 | 1.000000 0.731209 4.282233 14 | 1.000000 0.236833 3.486582 15 | 1.000000 0.969788 4.655492 16 | 1.000000 0.607492 3.965162 17 | 1.000000 0.358622 3.514900 18 | 1.000000 0.147846 3.125947 19 | 1.000000 0.637820 4.094115 20 | 1.000000 0.230372 3.476039 21 | 1.000000 0.070237 3.210610 22 | 1.000000 0.067154 3.190612 23 | 1.000000 0.925577 4.631504 24 | 1.000000 0.717733 4.295890 25 | 1.000000 0.015371 3.085028 26 | 1.000000 0.335070 3.448080 27 | 1.000000 0.040486 3.167440 28 | 1.000000 0.212575 3.364266 29 | 1.000000 0.617218 3.993482 30 | 1.000000 0.541196 3.891471 31 | 1.000000 0.045353 3.143259 32 | 1.000000 0.126762 3.114204 33 | 1.000000 0.556486 3.851484 34 | 1.000000 0.901144 4.621899 35 | 1.000000 0.958476 4.580768 36 | 1.000000 0.274561 3.620992 37 | 1.000000 0.394396 3.580501 38 | 1.000000 0.872480 4.618706 39 | 1.000000 0.409932 3.676867 40 | 1.000000 0.908969 4.641845 41 | 1.000000 0.166819 3.175939 42 | 1.000000 0.665016 4.264980 43 | 1.000000 0.263727 3.558448 44 | 1.000000 0.231214 3.436632 45 | 1.000000 0.552928 3.831052 46 | 1.000000 0.047744 3.182853 47 | 1.000000 0.365746 3.498906 48 | 1.000000 0.495002 3.946833 49 | 1.000000 0.493466 3.900583 50 | 1.000000 0.792101 4.238522 51 | 1.000000 0.769660 4.233080 52 | 1.000000 0.251821 3.521557 53 | 1.000000 0.181951 3.203344 54 | 1.000000 0.808177 4.278105 55 | 1.000000 0.334116 3.555705 56 | 1.000000 0.338630 3.502661 57 | 1.000000 0.452584 3.859776 58 | 1.000000 0.694770 4.275956 59 | 1.000000 0.590902 3.916191 60 | 1.000000 0.307928 3.587961 61 | 1.000000 0.148364 3.183004 62 | 1.000000 0.702180 4.225236 63 | 1.000000 0.721544 4.231083 64 | 1.000000 0.666886 4.240544 65 | 1.000000 0.124931 3.222372 66 | 1.000000 0.618286 4.021445 67 | 1.000000 0.381086 3.567479 68 | 1.000000 0.385643 3.562580 69 | 1.000000 0.777175 4.262059 70 | 1.000000 0.116089 3.208813 71 | 1.000000 0.115487 3.169825 72 | 1.000000 0.663510 4.193949 73 | 1.000000 0.254884 3.491678 74 | 1.000000 0.993888 4.533306 75 | 1.000000 0.295434 3.550108 76 | 1.000000 0.952523 4.636427 77 | 1.000000 0.307047 3.557078 78 | 1.000000 0.277261 3.552874 79 | 1.000000 0.279101 3.494159 80 | 1.000000 0.175724 3.206828 81 | 1.000000 0.156383 3.195266 82 | 1.000000 0.733165 4.221292 83 | 1.000000 0.848142 4.413372 84 | 1.000000 0.771184 4.184347 85 | 1.000000 0.429492 3.742878 86 | 1.000000 0.162176 3.201878 87 | 1.000000 0.917064 4.648964 88 | 1.000000 0.315044 3.510117 89 | 1.000000 0.201473 3.274434 90 | 1.000000 0.297038 3.579622 91 | 1.000000 0.336647 3.489244 92 | 1.000000 0.666109 4.237386 93 | 1.000000 0.583888 3.913749 94 | 1.000000 0.085031 3.228990 95 | 1.000000 0.687006 4.286286 96 | 1.000000 0.949655 4.628614 97 | 1.000000 0.189912 3.239536 98 | 1.000000 0.844027 4.457997 99 | 1.000000 0.333288 3.513384 100 | 1.000000 0.427035 3.729674 101 | 1.000000 0.466369 3.834274 102 | 1.000000 0.550659 3.811155 103 | 1.000000 0.278213 3.598316 104 | 1.000000 0.918769 4.692514 105 | 1.000000 0.886555 4.604859 106 | 1.000000 0.569488 3.864912 107 | 1.000000 0.066379 3.184236 108 | 1.000000 0.335751 3.500796 109 | 1.000000 0.426863 3.743365 110 | 1.000000 0.395746 3.622905 111 | 1.000000 0.694221 4.310796 112 | 1.000000 0.272760 3.583357 113 | 1.000000 0.503495 3.901852 114 | 1.000000 0.067119 3.233521 115 | 1.000000 0.038326 3.105266 116 | 1.000000 0.599122 3.865544 117 | 1.000000 0.947054 4.628625 118 | 1.000000 0.671279 4.231213 119 | 1.000000 0.434811 3.791149 120 | 1.000000 0.509381 3.968271 121 | 1.000000 0.749442 4.253910 122 | 1.000000 0.058014 3.194710 123 | 1.000000 0.482978 3.996503 124 | 1.000000 0.466776 3.904358 125 | 1.000000 0.357767 3.503976 126 | 1.000000 0.949123 4.557545 127 | 1.000000 0.417320 3.699876 128 | 1.000000 0.920461 4.613614 129 | 1.000000 0.156433 3.140401 130 | 1.000000 0.656662 4.206717 131 | 1.000000 0.616418 3.969524 132 | 1.000000 0.853428 4.476096 133 | 1.000000 0.133295 3.136528 134 | 1.000000 0.693007 4.279071 135 | 1.000000 0.178449 3.200603 136 | 1.000000 0.199526 3.299012 137 | 1.000000 0.073224 3.209873 138 | 1.000000 0.286515 3.632942 139 | 1.000000 0.182026 3.248361 140 | 1.000000 0.621523 3.995783 141 | 1.000000 0.344584 3.563262 142 | 1.000000 0.398556 3.649712 143 | 1.000000 0.480369 3.951845 144 | 1.000000 0.153350 3.145031 145 | 1.000000 0.171846 3.181577 146 | 1.000000 0.867082 4.637087 147 | 1.000000 0.223855 3.404964 148 | 1.000000 0.528301 3.873188 149 | 1.000000 0.890192 4.633648 150 | 1.000000 0.106352 3.154768 151 | 1.000000 0.917886 4.623637 152 | 1.000000 0.014855 3.078132 153 | 1.000000 0.567682 3.913596 154 | 1.000000 0.068854 3.221817 155 | 1.000000 0.603535 3.938071 156 | 1.000000 0.532050 3.880822 157 | 1.000000 0.651362 4.176436 158 | 1.000000 0.901225 4.648161 159 | 1.000000 0.204337 3.332312 160 | 1.000000 0.696081 4.240614 161 | 1.000000 0.963924 4.532224 162 | 1.000000 0.981390 4.557105 163 | 1.000000 0.987911 4.610072 164 | 1.000000 0.990947 4.636569 165 | 1.000000 0.736021 4.229813 166 | 1.000000 0.253574 3.500860 167 | 1.000000 0.674722 4.245514 168 | 1.000000 0.939368 4.605182 169 | 1.000000 0.235419 3.454340 170 | 1.000000 0.110521 3.180775 171 | 1.000000 0.218023 3.380820 172 | 1.000000 0.869778 4.565020 173 | 1.000000 0.196830 3.279973 174 | 1.000000 0.958178 4.554241 175 | 1.000000 0.972673 4.633520 176 | 1.000000 0.745797 4.281037 177 | 1.000000 0.445674 3.844426 178 | 1.000000 0.470557 3.891601 179 | 1.000000 0.549236 3.849728 180 | 1.000000 0.335691 3.492215 181 | 1.000000 0.884739 4.592374 182 | 1.000000 0.918916 4.632025 183 | 1.000000 0.441815 3.756750 184 | 1.000000 0.116598 3.133555 185 | 1.000000 0.359274 3.567919 186 | 1.000000 0.814811 4.363382 187 | 1.000000 0.387125 3.560165 188 | 1.000000 0.982243 4.564305 189 | 1.000000 0.780880 4.215055 190 | 1.000000 0.652565 4.174999 191 | 1.000000 0.870030 4.586640 192 | 1.000000 0.604755 3.960008 193 | 1.000000 0.255212 3.529963 194 | 1.000000 0.730546 4.213412 195 | 1.000000 0.493829 3.908685 196 | 1.000000 0.257017 3.585821 197 | 1.000000 0.833735 4.374394 198 | 1.000000 0.070095 3.213817 199 | 1.000000 0.527070 3.952681 200 | 1.000000 0.116163 3.129283 201 | -------------------------------------------------------------------------------- /Experiments/LR_ex1.txt: -------------------------------------------------------------------------------- 1 | 1.000000 0.635975 4.093119 2 | 1.000000 0.552438 3.804358 3 | 1.000000 0.855922 4.456531 4 | 1.000000 0.083386 3.187049 5 | 1.000000 0.975802 4.506176 6 | 1.000000 0.181269 3.171914 7 | 1.000000 0.129156 3.053996 8 | 1.000000 0.605648 3.974659 9 | 1.000000 0.301625 3.542525 10 | 1.000000 0.698805 4.234199 11 | 1.000000 0.226419 3.405937 12 | 1.000000 0.519290 3.932469 13 | 1.000000 0.354424 3.514051 14 | 1.000000 0.118380 3.105317 15 | 1.000000 0.512811 3.843351 16 | 1.000000 0.236795 3.576074 17 | 1.000000 0.353509 3.544471 18 | 1.000000 0.481447 3.934625 19 | 1.000000 0.060509 3.228226 20 | 1.000000 0.174090 3.300232 21 | 1.000000 0.806818 4.331785 22 | 1.000000 0.531462 3.908166 23 | 1.000000 0.853167 4.386918 24 | 1.000000 0.304804 3.617260 25 | 1.000000 0.612021 4.082411 26 | 1.000000 0.620880 3.949470 27 | 1.000000 0.580245 3.984041 28 | 1.000000 0.742443 4.251907 29 | 1.000000 0.110770 3.115214 30 | 1.000000 0.742687 4.234319 31 | 1.000000 0.574390 3.947544 32 | 1.000000 0.986378 4.532519 33 | 1.000000 0.294867 3.510392 34 | 1.000000 0.472125 3.927832 35 | 1.000000 0.872321 4.631825 36 | 1.000000 0.843537 4.482263 37 | 1.000000 0.864577 4.487656 38 | 1.000000 0.341874 3.486371 39 | 1.000000 0.097980 3.137514 40 | 1.000000 0.757874 4.212660 41 | 1.000000 0.877656 4.506268 42 | 1.000000 0.457993 3.800973 43 | 1.000000 0.475341 3.975979 44 | 1.000000 0.848391 4.494447 45 | 1.000000 0.746059 4.244715 46 | 1.000000 0.153462 3.019251 47 | 1.000000 0.694256 4.277945 48 | 1.000000 0.498712 3.812414 49 | 1.000000 0.023580 3.116973 50 | 1.000000 0.976826 4.617363 51 | 1.000000 0.624004 4.005158 52 | 1.000000 0.472220 3.874188 53 | 1.000000 0.390551 3.630228 54 | 1.000000 0.021349 3.145849 55 | 1.000000 0.173488 3.192618 56 | 1.000000 0.971028 4.540226 57 | 1.000000 0.595302 3.835879 58 | 1.000000 0.097638 3.141948 59 | 1.000000 0.745972 4.323316 60 | 1.000000 0.676390 4.204829 61 | 1.000000 0.488949 3.946710 62 | 1.000000 0.982873 4.666332 63 | 1.000000 0.296060 3.482348 64 | 1.000000 0.228008 3.451286 65 | 1.000000 0.671059 4.186388 66 | 1.000000 0.379419 3.595223 67 | 1.000000 0.285170 3.534446 68 | 1.000000 0.236314 3.420891 69 | 1.000000 0.629803 4.115553 70 | 1.000000 0.770272 4.257463 71 | 1.000000 0.493052 3.934798 72 | 1.000000 0.631592 4.154963 73 | 1.000000 0.965676 4.587470 74 | 1.000000 0.598675 3.944766 75 | 1.000000 0.351997 3.480517 76 | 1.000000 0.342001 3.481382 77 | 1.000000 0.661424 4.253286 78 | 1.000000 0.140912 3.131670 79 | 1.000000 0.373574 3.527099 80 | 1.000000 0.223166 3.378051 81 | 1.000000 0.908785 4.578960 82 | 1.000000 0.915102 4.551773 83 | 1.000000 0.410940 3.634259 84 | 1.000000 0.754921 4.167016 85 | 1.000000 0.764453 4.217570 86 | 1.000000 0.101534 3.237201 87 | 1.000000 0.780368 4.353163 88 | 1.000000 0.819868 4.342184 89 | 1.000000 0.173990 3.236950 90 | 1.000000 0.330472 3.509404 91 | 1.000000 0.162656 3.242535 92 | 1.000000 0.476283 3.907937 93 | 1.000000 0.636391 4.108455 94 | 1.000000 0.758737 4.181959 95 | 1.000000 0.778372 4.251103 96 | 1.000000 0.936287 4.538462 97 | 1.000000 0.510904 3.848193 98 | 1.000000 0.515737 3.974757 99 | 1.000000 0.437823 3.708323 100 | 1.000000 0.828607 4.385210 101 | 1.000000 0.556100 3.927788 102 | 1.000000 0.038209 3.187881 103 | 1.000000 0.321993 3.444542 104 | 1.000000 0.067288 3.199263 105 | 1.000000 0.774989 4.285745 106 | 1.000000 0.566077 3.878557 107 | 1.000000 0.796314 4.155745 108 | 1.000000 0.746600 4.197772 109 | 1.000000 0.360778 3.524928 110 | 1.000000 0.397321 3.525692 111 | 1.000000 0.062142 3.211318 112 | 1.000000 0.379250 3.570495 113 | 1.000000 0.248238 3.462431 114 | 1.000000 0.682561 4.206177 115 | 1.000000 0.355393 3.562322 116 | 1.000000 0.889051 4.595215 117 | 1.000000 0.733806 4.182694 118 | 1.000000 0.153949 3.320695 119 | 1.000000 0.036104 3.122670 120 | 1.000000 0.388577 3.541312 121 | 1.000000 0.274481 3.502135 122 | 1.000000 0.319401 3.537559 123 | 1.000000 0.431653 3.712609 124 | 1.000000 0.960398 4.504875 125 | 1.000000 0.083660 3.262164 126 | 1.000000 0.122098 3.105583 127 | 1.000000 0.415299 3.742634 128 | 1.000000 0.854192 4.566589 129 | 1.000000 0.925574 4.630884 130 | 1.000000 0.109306 3.190539 131 | 1.000000 0.805161 4.289105 132 | 1.000000 0.344474 3.406602 133 | 1.000000 0.769116 4.251899 134 | 1.000000 0.182003 3.183214 135 | 1.000000 0.225972 3.342508 136 | 1.000000 0.413088 3.747926 137 | 1.000000 0.964444 4.499998 138 | 1.000000 0.203334 3.350089 139 | 1.000000 0.285574 3.539554 140 | 1.000000 0.850209 4.443465 141 | 1.000000 0.061561 3.290370 142 | 1.000000 0.426935 3.733302 143 | 1.000000 0.389376 3.614803 144 | 1.000000 0.096918 3.175132 145 | 1.000000 0.148938 3.164284 146 | 1.000000 0.893738 4.619629 147 | 1.000000 0.195527 3.426648 148 | 1.000000 0.407248 3.670722 149 | 1.000000 0.224357 3.412571 150 | 1.000000 0.045963 3.110330 151 | 1.000000 0.944647 4.647928 152 | 1.000000 0.756552 4.164515 153 | 1.000000 0.432098 3.730603 154 | 1.000000 0.990511 4.609868 155 | 1.000000 0.649699 4.094111 156 | 1.000000 0.584879 3.907636 157 | 1.000000 0.785934 4.240814 158 | 1.000000 0.029945 3.106915 159 | 1.000000 0.075747 3.201181 160 | 1.000000 0.408408 3.872302 161 | 1.000000 0.583851 3.860890 162 | 1.000000 0.497759 3.884108 163 | 1.000000 0.421301 3.696816 164 | 1.000000 0.140320 3.114540 165 | 1.000000 0.546465 3.791233 166 | 1.000000 0.843181 4.443487 167 | 1.000000 0.295390 3.535337 168 | 1.000000 0.825059 4.417975 169 | 1.000000 0.946343 4.742471 170 | 1.000000 0.350404 3.470964 171 | 1.000000 0.042787 3.113381 172 | 1.000000 0.352487 3.594600 173 | 1.000000 0.590736 3.914875 174 | 1.000000 0.120748 3.108492 175 | 1.000000 0.143140 3.152725 176 | 1.000000 0.511926 3.994118 177 | 1.000000 0.496358 3.933417 178 | 1.000000 0.382802 3.510829 179 | 1.000000 0.252464 3.498402 180 | 1.000000 0.845894 4.460441 181 | 1.000000 0.132023 3.245277 182 | 1.000000 0.442301 3.771067 183 | 1.000000 0.266889 3.434771 184 | 1.000000 0.008575 2.999612 185 | 1.000000 0.897632 4.454221 186 | 1.000000 0.533171 3.985348 187 | 1.000000 0.285243 3.557982 188 | 1.000000 0.377258 3.625972 189 | 1.000000 0.486995 3.922226 190 | 1.000000 0.305993 3.547421 191 | 1.000000 0.277528 3.580944 192 | 1.000000 0.750899 4.268081 193 | 1.000000 0.694756 4.278096 194 | 1.000000 0.870158 4.517640 195 | 1.000000 0.276457 3.555461 196 | 1.000000 0.017761 3.055026 197 | 1.000000 0.802046 4.354819 198 | 1.000000 0.559275 3.894387 199 | 1.000000 0.941305 4.597773 200 | 1.000000 0.856877 4.523616 201 | -------------------------------------------------------------------------------- /Experiments/Questions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title : JAVA实验 3 | --- 4 | 5 | 6 | [TOC] 7 | 8 | # 必做题 9 | 10 | ## 实验1:二分法求函数的根 11 | 12 | ### 函数 13 | $$ 14 | f(x) = x^3 -10 x + 23 15 | $$ 16 | 17 | ### 初始值 18 | 19 | - $x_{low} = -10.0$ 20 | - $x_{high} = 5.0$ 21 | - $\delta = 0.001$ 22 | 23 | ### 二分法 24 | 25 | 1. $f(x_{high}) \cdot F(x_{low}) < 0$ 26 | 2. $x_c = \frac{x_{high} + x_{low}}{2}$ 27 | 3. 当$f(x_c) = 0$时,即得到根值,将$x_c$作为结果输出打印并退出程序 28 | 4. 否则,当$f(x_c) \neq 0$时,执行下述步骤$5$或$6$ 29 | 5. 当$f(x_{high}) \cdot f(x_{c}) < 0$时,$x_{low}= c$ 30 | 6. 当$f(x_{low}) \cdot f(x_{c}) < 0$时,$x_{high}= c$ 31 | 7. 当$|x_{high}-x_{low}| \le \delta$时,将$x_c$作为结果输出打印并退出程序,否则执行步骤$2$。 32 | 33 | 34 | 35 | ## 实验2:求$10,000,000$内最大的素数 36 | 37 | ### 参考程序:求解100以内的全部素数 38 | 39 | ~~~java 40 | public class PrimeApp { 41 | public static void main(String[] args) { 42 | int m, n;// 变量n为要判断的数字 43 | System.out.println("100以内的素数有:"); 44 | A: for (n = 2; n <= 100; n++) { 45 | for (m = 2; m < n / 2; m++) { 46 | if (n % m == 0) 47 | continue A; 48 | // 如果能被整除则变量n肯定不是素数,跳出内层循环 49 | } 50 | 51 | System.out.print(n + " " + "\t");//输出素数 52 | } 53 | } 54 | } 55 | ~~~ 56 | 57 | 58 | 59 | ## 实验3:K-Means算法实现对数据的聚类分析 60 | 61 | K-Means算法的基本思想是初始随机给定K个簇中心,按照最邻近原则把待分类样本点分到各个簇。 62 | 然后按平均法重新计算各个簇的质心,从而确定新的簇心。 63 | 一直迭代,直到簇心的移动距离小于某个给定的值。 64 | 65 | ### 工作原理是: 66 | 67 | ~~~ 68 | 选择K个点作为初始质心(随机选择) 69 | Repeat 70 | 计算数据集中每个点到各个簇的质心的距离,将数据点分配到距离最近的簇 71 | 重新计算每个簇中所有点的均值并将该均值作为质心 72 | Until 簇不发生变化或达到最大迭代次数 73 | ~~~ 74 | 75 | - 其中K是用户指定的参数,即所期望的簇的个数。 76 | - 常用的距离度量方法为:欧几里得距离 77 | - 簇的质心都是其均值,即向量各维取平均即可 78 | 79 | ### Data Sets: 80 | 81 | - KMeans_Set.txt 82 | - KMeans_Set2.txt 83 | 84 | 85 | 86 | ## 实验4:线性回归(Linear Regression)找到最佳拟合直线 87 | 88 | 在统计学中,线性回归(Linear Regression)是利用称为线性回归方程的最小平方函数对一个或多个自变量和因变量之间关系进行建模的一种回归分析。 89 | 90 | 设直线方程为 91 | $$ 92 | f(x) = A x + B 93 | $$ 94 | 95 | 设数据集为$\{(x_k,y_k)\}_{k=1}^N $ 96 | 97 | 误差均值为: 98 | 99 | $$E_2(f)^2 = \frac{1}{N} \sum_{k=1}^N (Ax_k + B - y_k)^2$$ 100 | 101 | 若 102 | $$ 103 | \frac{\partial E (A, B)}{\partial A} = 0 104 | $$ 105 | $$ 106 | \frac{\partial E (A, B)}{\partial B} = 0 107 | $$ 108 | 则 109 | $$ 110 | 0 = \sum_{k=1}^N (A x_k^2 + B x_k - x_k y_k) = A \sum_{k=1}^N x_k^2 + B \sum_{k=1}^N x_k - \sum_{k=1}^N x_k y_k 111 | $$ 112 | $$ 113 | 0 = \sum_{k=1}^N (A x_k + B - y_k) = A \sum_{k=1}^N x_k + NB - \sum_{k=1}^N y_k 114 | $$ 115 | 即: 116 | $$ 117 | \left( \sum_{k=1}^N x_k^2 \right) A + \left( \sum_{k=1}^N x_k \right) B = \sum_{k=1}^N x_k y_k 118 | $$ 119 | $$ 120 | \left( \sum_{k=1}^N x_k \right) A + N B = \sum_{k=1}^N y_k 121 | $$ 122 | 123 | 最后根据上述两式可以求出$A$和$B$ 124 | 125 | ### Data Sets: 126 | 127 | - LR_ex0.txt 128 | - LR_ex1.txt 129 | 130 | 131 | ## 实验5:统计学生成绩 132 | 133 | ### 要求: 134 | 135 | - 从指定的文本文件读取成绩 136 | - 获取最高成绩和最低成绩 137 | - 计算所有学生的平均成绩 138 | - 分别统计$60$~$69$,$70$~$79$,$80$~$89$,$90~100$分数段的学生人数 139 | - 所有结果要输出到一个文本文件 140 | 141 | ### Data Sets: 142 | 143 | - score.cvs 144 | 145 | 146 | 147 | # 选做题 148 | 149 | - 至少要选择三道选做题, 150 | - 多做有加分。 151 | 152 | 153 | ## 实验6:图形用户界面 154 | 155 | ### 模拟计算器 156 | 157 | 复习教课书上的模拟计算器的程序例子,并实现该程序 158 | 159 | ### 五子棋的游戏 160 | 161 | 实验要求: 162 | 163 | - 棋盘为10行10列,棋盘底色可自己设定,棋盘格子间有一定间隙。 164 | 165 | - 本游戏为单机版,故而为了模拟双方下棋的效果,可一人下棋时显示“O”, 另一人下棋时显示“X”,以示区分并相互交替。并且,一个格子如果已经下过棋子,则不可再改变它上的棋子,即不能再更改其上显示的字符,或者说按钮变得不可用。如下图所示。 166 | 167 | ![](wz1.png) 168 | 169 | - 游戏规则: 170 | 当同一行或同一列或同一条对角线上有连续的五个相同棋子时判 赢。若最终棋盘满了仍未有五个相同棋子连成一线,则判输。若未有这两种情况,则继续下棋。(注:此功能需要一定的算法设计和数据结构知识,如果时间不足,可不做) 171 | 172 | - 无论最终是赢或输,都自动弹出一个消息框,并给出相应的提示,如下图所示。(注:可将本要求简化为,针对棋盘中的某两个特定格子,一个格子单击后弹出成功对话框,一个格子弹出失败对话框) 173 | 174 | ![](wz2.png) 175 | ![](wz3.png) 176 | 177 | 178 | 179 | ## 实验7:JDBC方式操作数据库 180 | 181 | ### 实现一个简单的信息管理系统 182 | 183 | 实现如下功能: 184 | 185 | - 创建信息表; 186 | - 实现记录的查询,修改,插入,删除; 187 | - 实现记录的统计; 188 | - 纪录数据的导入和导出(Excel文件) 189 | 190 | ### 例如 191 | 192 | - 以下例子仅供参考,但必须要完成上述所列的基本功能。 193 | - 可根据实际需要作适当的修改,补充。 194 | 195 | #### 学生信息管理系统 196 | 197 | - 创建student表,包含学生的学号、姓名、年龄信息。 198 | - 根据学号,可以查询到学生的姓名和年龄; 199 | - 给定学生的学号、姓名、年龄,在表中追加一行信息; 200 | - 给定学生的学号,可以从表中删除该学生的信息; 201 | 202 | #### 图书信息管理系统 203 | 204 | - 创建图书信息表,包含图书的书名、书号、作者、出版日期信息。 205 | - 根据书名,可以查询到图书的书号、作者、出版日期信息; 206 | - 给定图书的书名、书号、作者、出版日期信息,在表中追加一行信息; 207 | - 给定图书的书名,可以从表中删除该图书的信息; 208 | 209 | #### 商品信息管理系统 210 | 211 | - 创建商品信息表,包含商品的名称、规格、生产厂商、价格信息。 212 | - 根据商品的名称,可以查询到商品的、规格、生产厂商、价格信息; 213 | - 给定商品的名称、规格、生产厂商、价格信息,在表中追加一行信息; 214 | - 给定商品的名称,可以从表中删除该商品的信息; 215 | 216 | 217 | 218 | ## 实验8:网络编程基础 219 | 220 | 实现Java爬虫,抓去设定网站的信息 221 | 222 | - 设定一家知名的信息网站,例如百度新闻,今日头条,新浪新闻,网易新闻等, 223 | - 使用InetAddress类的方法获取设定网站的主机的IP地址; 224 | - 获取本地机的名称和IP地址。 225 | - 使用URL类下载首页信息, 226 | - 分析首页信息,进行信息过滤,将新闻报道的正文进行分门别类的整理。 227 | 228 | 229 | ## 实验9:二维码的编码和解码 230 | 231 | 利用开源的QR库,实现一个简单的二维码的编码和解码应用程序。 232 | 233 | 实现如下基本功能: 234 | 235 | - 将输入的一段字符串或URL转换为一幅对应的二维码图片; 236 | - 从一幅输入的二维码图片之中解析出对应的字符串或URL。 237 | 238 | 参考开源的QR库: 239 | 240 | 241 | 242 | 243 | ## 实验10:重复文件的查询 244 | 245 | 实现如下基本功能: 246 | 247 | - 设定需要查询的文件目录; 248 | - 在遍历整个文件目录的同时,获取每个文件的MD5 checksum值; 249 | - 若在遍历工程之中若发现有的MD5 checksum值相同的文件时,将两个文件进行对比,确认两个文件是否相同; 250 | - 若判断两个文件相同时,输出结果提示用户两个重复文件的路径以及文件名。 251 | 252 | 253 | 254 | # 实验报告的说明 255 | 256 | ## 时间和地点 257 | 258 | |No|时间|地点| 259 | |:---|:---|:---| 260 | |1|6月6日(1,2)|B3-138| 261 | |2|6月12日(1,2)|B3-138| 262 | |3|6月13日(1,2)|B3-138| 263 | |4|6月20日(1,2)|B3-138| 264 | 265 | ## 提交的实验报告格式 266 | 267 | - DOC 268 | - PDF(如使用MarkDown或Latex,请转换成PDF) 269 | - 学院规定的实验报告封面 270 | 271 | ## 实验报告文件名 272 | 273 | >学号\_姓名.doc 274 | 275 | 或 276 | 277 | >学号\_姓名.pdf 278 | 279 | ## 实验报告内容 280 | 281 | ### 学院规定的实验报告封面 282 | 283 | ### 每个实验题目设为单独的一个章节 284 | 285 | 包括: 286 | 287 | - 实验题目 288 | 289 | - 问题分析 290 | 需要解决的技术问题,以及采用的技术方案 291 | 292 | - 实验的具体步骤 293 | 开发环境的设定,例如数据库的创建,选用第三方开源库的设定; 294 | 类以及数据结构的设计(UML); 295 | 代码开发过程以及测试(必要的截图) 296 | 297 | - 实现程序的完整代码 298 | 299 | - 实验结果以及总结 300 | 运行结果,对应结果的截图 301 | 对结果的分析 302 | 303 | --- 304 | 305 | 本文档 Github : 306 | https://github.com/bushehui/Java_tutorial 307 | 308 | 311 | 312 | 315 | 316 | 317 | 318 | 319 | -------------------------------------------------------------------------------- /Experiments/Questions_En.md: -------------------------------------------------------------------------------- 1 | --- 2 | title : Practical Experiments of the Java Programing Language 3 | --- 4 | 5 | 6 | [TOC] 7 | 8 | 9 | #Basic Experiments 10 | 11 | ##1:Bisection method 12 | 13 | ###Function : 14 | 15 | $ 16 | f(x) = x^3 -10 x + 23 17 | $ 18 | 19 | ###Initial values : 20 | 21 | - $x_{low} = -10.0$ 22 | - $x_{high} = 5.0$ 23 | - $\delta = 0.001$ 24 | 25 | ###Root-finding procedure : 26 | 27 | 1. $f(x_{high}) \cdot F(x_{low}) < 0$ 28 | 2. $x_c = \frac{x_{high} + x_{low}}{2}$ 29 | 3. if $f(x_c) = 0$,let $x_c$ as the result and exit the procedure 30 | 4. if $f(x_c) \neq 0$,go to $5$ or $6$ 31 | 5. if $f(x_{high}) \cdot f(x_{c}) < 0$,$x_{low}= c$ 32 | 6. if $f(x_{low}) \cdot f(x_{c}) < 0$,$x_{high}= c$ 33 | 7. if $|x_{high}-x_{low}| \le \delta$,let $x_c$as the result and exit the procedure,else goto $2$。 34 | 35 | 36 | 37 | ##2:Find the largest prime number less than $10,000,000$ 38 | 39 | ###Reference program:Finding all prime numbers less than $100$ 40 | 41 | ~~~java 42 | public class PrimeApp { 43 | public static void main(String[] args) { 44 | int m, n;// To determine whether the variable n is the prime number 45 | System.out.println("The prime numbers less than 100:"); 46 | A: for (n = 2; n <= 100; n++) { 47 | for (m = 2; m < n / 2; m++) { 48 | if (n % m == 0) 49 | continue A; 50 | // If the variable n is divisible, out of the inner loop 51 | } 52 | 53 | System.out.print(n + " " + "\t");//output the prime number 54 | } 55 | } 56 | } 57 | ~~~ 58 | 59 | 60 | 61 | ##3:Implementation of the K-Means algorithm for the data clusering 62 | 63 | 70 | 71 | ###Procedure: 72 | 73 | ~~~ 74 | Randomly assign K cluster centers as the initial cluster centers 75 | 76 | Repeat 77 | - Calculate the distance between each point in the data set and the center of each cluster 78 | - Assign all of the data point to the nearest cluster 79 | 80 | - Recalculate the centers of each cluster, then update the new cluster centers. 81 | 82 | Until the movement distance of the cluster centers is less than a given value. 83 | ~~~ 84 | 85 | Where 86 | 87 | - K is the user-specified parameter, the number of clusters expected. 88 | - Distance : Euclidean distance 89 | 90 | ###Data Sets: 91 | 92 | - KMeans_Set.txt 93 | - KMeans_Set2.txt 94 | 95 | 96 | 97 | ##4:Linear Regression 98 | 99 | In statistics, linear regression is analysis method to find the relationship between one or more independent variables and dependent variables by using the least squares function. 100 | 101 | ###Principle 102 | 103 | - Suppose the linear function: 104 | $ 105 | f(x) = A x + B 106 | $ 107 | 108 | - The training data set 109 | $\{(x_k,y_k)\}_{k=1}^N $ 110 | 111 | - The mean square error 112 | $E_2(f)^2 = \frac{1}{N} \sum_{k=1}^N (Ax_k + B - y_k)^2$ 113 | 114 | - If $\frac{\partial E (A, B)}{\partial A} = 0$ and $\frac{\partial E (A, B)}{\partial B} = 0$ 115 | 116 | - Then 117 | $ 118 | 0 = \sum_{k=1}^N (A x_k^2 + B x_k - x_k y_k) = A \sum_{k=1}^N x_k^2 + B \sum_{k=1}^N x_k - \sum_{k=1}^N x_k y_k 119 | $ 120 | $ 121 | 0 = \sum_{k=1}^N (A x_k + B - y_k) = A \sum_{k=1}^N x_k + NB - \sum_{k=1}^N y_k 122 | $ 123 | 124 | - Finally, the $A$和$B$ can be calculated by 125 | $ 126 | \left( \sum_{k=1}^N x_k^2 \right) A + \left( \sum_{k=1}^N x_k \right) B = \sum_{k=1}^N x_k y_k 127 | $ 128 | $ 129 | \left( \sum_{k=1}^N x_k \right) A + N B = \sum_{k=1}^N y_k 130 | $ 131 | 132 | 133 | 134 | ###Data Sets: 135 | 136 | - LR_ex0.txt 137 | - LR_ex1.txt 138 | 139 | 140 | 141 | ##5:Student achievement statistics 142 | 143 | ###Requirements: 144 | 145 | - Input the data from the specified file 146 | - Get the highest score and the lowest score 147 | - Calculate the average score for all students 148 | - Get the score histogram between $60$~$69$,$70$~$79$,$80$~$89$ and $90~100$. 149 | 150 | ###Data Sets: 151 | 152 | - score.cvs 153 | 154 | 155 | 156 | #Optional Experiments 157 | 158 | - Select at least three optional problems, 159 | 160 | ##6:Graphical user interface (GUI) 161 | 162 | ###Simulation of the simple calculator 163 | 164 | 165 | ###Gomoku game 166 | 167 | 168 | 169 | ##7:Database operation 170 | 171 | ###A simple information management system 172 | 173 | To achieve the following functions: 174 | 175 | - Create information table; 176 | - query, modify, insert, delete the record; 177 | - statistics of records; 178 | - Import and export of recorded data (Excel file) 179 | 180 | ###E.g. 181 | 182 | - Reference only, 183 | - The basic functions listed above must be completed. 184 | 185 | 186 | ####Student Information Management System 187 | 188 | - Create a student table that contains the student's ID, name, and age information. 189 | - According to the ID, you can check the student's name and age; 190 | - Add a new record of a given student's ID, name and age into the database; 191 | - Remove the student's record from the database according to the student's ID; 192 | 193 | #### Book information management system 194 | 195 | - Create a book information table that contains the book title, book number, author, publication date information. 196 | - According to the title, you can query the book number, author, publication date information; 197 | - Add a new record of a given book's title, book number, author, publication date information into the database; 198 | - Remove the book's record from the database according to the book's title 199 | 200 | 201 | 202 | ##8:Network programming 203 | 204 | Implement a Java crawler 205 | 206 | - Given a well-known website, such as Zhihu, Douban; 207 | - Use the InetAddress class to get the IP address of the website; 208 | - Get the name and IP address of the local machine; 209 | - Use the URL class to download the webpage information, 210 | - Filter and analysis the webpage, save the information as the text file. 211 | 212 | 213 | 214 | ##9:Coding and decoding of two-dimensional code 215 | 216 | Using an open source QR library to implement a simple two-dimensional code encoding and decoding application. 217 | 218 | The basic functions: 219 | 220 | - Convert the input of a string or URL into a corresponding two-dimensional code picture; 221 | - Parse the corresponding string or URL from an input 2D code image. 222 | 223 | Reference: 224 | 225 | 226 | 227 | 228 | ##10 :Duplicate file detection 229 | 230 | The basic functions: 231 | 232 | - set the the file directory; 233 | - get the MD5 checksum value of each file while traversing the entire file directory; 234 | - If the MD5 checksum values are same, compared the documents byte by byte to confirm whether the documents are the same; 235 | - If the files are judged to be the same, the output prompts the user for the path and file name of the duplicate files. 236 | 237 | 238 | 239 | 240 | #Requirements 241 | 242 | ##Document fomat 243 | 244 | - MS-Word 245 | - PDF 246 | 247 | 248 | ##File name 249 | 250 | >ID\_YourName.doc 251 | 252 | or 253 | 254 | >ID\_YourName.pdf 255 | 256 | 257 | ##Content 258 | 259 | ### The report cover 260 | 261 | ### Each experimental topic 262 | 263 | - Experimental topics 264 | 265 | - problem analysis 266 | 267 | - the specific steps of the experiment 268 | 269 | Setting development environment, such as creating a database, choose Preferences third party open source libraries; 270 | 271 | Class and data structure design (UML); 272 | 273 | Code development process and testing (necessary screenshots) 274 | 275 | - Complete code 276 | 277 | - experimental results and summary 278 | 279 | Results and the corresponding screenshot 280 | 281 | Analysis of the results 282 | 283 | Comment and discussion 284 | 285 | 286 | --- 287 | 288 | You can get this document and datasets from Github : 289 | https://github.com/bushehui/Java_tutorial 290 | 291 | 294 | 295 | 298 | 299 | 300 | 301 | 302 | -------------------------------------------------------------------------------- /Experiments/score.csv: -------------------------------------------------------------------------------- 1 | 1;84 2;60 3;79 4;79 5;81 6;49 7;56 8;78 9;67 10;61 11;67 12;88 13;73 14;54 15;82 16;71 17;76 18;86 19;73 20;83 21;60 22;59 23;68 24;51 25;74 26;53 27;22 28;89 29;76 30;97 31;60 32;63 33;85 34;86 35;95 36;91 37;83 38;73 39;61 40;67 41;77 42;77 43;63 44;67 45;34 46;75 47;54 48;50 49;65 50;68 51;82 52;46 -------------------------------------------------------------------------------- /Experiments/wz1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/Experiments/wz1.png -------------------------------------------------------------------------------- /Experiments/wz2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/Experiments/wz2.png -------------------------------------------------------------------------------- /Experiments/wz3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/Experiments/wz3.png -------------------------------------------------------------------------------- /ch1.md: -------------------------------------------------------------------------------- 1 | 2 | --- 3 | title : Java 语言概述 4 | --- 5 | 6 | [TOC] 7 | 8 | # Java语言概述 9 | 10 | ## 什么是 Java? 11 | Java是由Sun Microsystems在1995年首先发布的编程语言和计算平台。 12 | Java快速、安全、可靠。从笔记本电脑到数据中心,从游戏控制台到科学超级计算机,从手机到互联网,Java 无处不在! 13 | 14 | Java是几乎所有类型的网络应用程序的基础,也是开发和提供嵌入式和移动应用程序、游戏、基于Web的内容和企业软件的全球标准。 15 | 16 | Java在全球各地有超过$900$万的开发人员,使您能够高效地开发、部署和使用精彩的应用程序和服务。 17 | 18 | - $97\%$的企业桌面运行 Java 19 | - 全球有$900$万Java 开发人员 20 | - 开发人员的头号选择 21 | - 排名第一的部署平台 22 | - __Android系统__ 23 | - __Hadoop MapReduce__ 24 | 25 | 32 | 33 | 34 | ## 简史 35 | 36 | - __名字的来源__:Java是印度尼西亚爪哇岛的英文名称,因盛产咖啡而闻名。 37 | 38 | Forward and Backward 39 | 40 | 41 | 42 | - __标识__: 一杯正冒着热气的咖啡。
43 | Forward and Backward 44 | 45 | Java语言其实是有个曾用名叫Oak,而且起这个名字的时候也是很随心的,只是因为看到了窗口外的一颗橡树(只是因为面向窗外多看了你一眼~),所以就叫为Oak,但Oak这个名字已经被注册。最后他们以Java这个名字命名了这个语言,据说是Sun公司的程序猿们都很喜欢喝咖啡,而且对爪哇岛的一种咖啡印象很深,所以就有了Java这个经典的名字和咖啡的图标。 46 | 47 | "I named Java," said Kim Polese, then the Oak product manager and now CEO of Marimba Inc. "I spent a lot of time and energy on naming Java because I wanted to get precisely the right name. I wanted something that reflected the essence of the technology: dynamic, revolutionary, lively, fun. Because this programming language was so unique, I was determined to avoid nerdy names. I also didn't want anything with 'Net' or 'Web' in it, because I find those names very forgettable. I wanted something that was cool, unique, and easy to spell and fun to say.yin'yong 48 | 49 | - 发展历史: 50 | 51 | Time| Event 52 | :------------ |:------------- 53 | 1995年5月23日 | Java语言诞生 54 | 1996年1月21日 | JDK-JDK1.0诞生 55 | 1997年2月18日 | JDK1.1发布 56 | 1998年12月8日 | JAVA2企业平台J2EE发布 57 | 1999年6月 | SUN公司发布Java的三个版本:标准版(J2SE)、企业版(J2EE)和微型版(J2ME) 58 | 2000年5月8日 | JDK1.3发布 59 | 2000年5月29日 | JDK1.4发布 60 | 2001年9月24日 | J2EE1.3发布 61 | 2002年2月26日 | J2SE1.4发布,自此Java的计算能力有了大幅提升 2004年9月30日 | J2SE1.5发布,更名为Java SE 5 62 | 2006年12月11日 | Java SE 6发布 63 | 2009年12月 | Java EE 6发布 64 | 2011年7月28日 | Java SE 7发布 65 | 2014年3月28日 | Java SE 8发布 66 | 2017年9月21日 | Java SE 9发表 67 | 2018年3月21日 | Java SE 10发表 68 | 69 | 70 | 2010年11月,由于Oracle公司对于Java社区的不友善,因此Apache扬言将退出JCP[14] 71 | 72 | - 2006年SUN在JavaOne公布Java 开放源代码项目,并推出__OpenJDK__项目。 73 | 74 | 75 | - James Gosling(詹姆斯·戈士林) 76 | 77 | Java编程语言的共同创始人之一,一般公认他为“Java之父”。 78 | 79 | 80 | ![](fig/james_gosling_java.jpg) 81 | 82 | 83 | 84 | 85 | ## 为何选择Java 86 | 87 | - Java已由专业的 Java 开发人员、设计师和爱好者团体进行测试、完善、扩展和验证。 88 | - Java 旨在竭尽所能为最广泛的计算平台开发可移植的高性能应用程序。通过使应用程序在异构环境之间可用,企业可以提供更多的服务,提高最终用户生产力并加强沟通与协作,从而显著降低企业和消费类应用程序的拥有成本。 89 | 90 | ### Java 是开发人员的无价之宝: 91 | 92 | - 在一个平台上编写软件,然后即可在几乎所有其他平台上运行 93 | - 创建可在 Web 浏览器中运行并可访问可用 Web 服务的程序 94 | - 开发适用于在线论坛、存储、投票、HTML 格式处理以及其他用途的服务器端应用程序 95 | - 将采用 Java 语言的应用程序或服务组合在一起,构成高度定制的应用程序或服务 96 | - 为移动电话、远程处理器、微控制器、无线模块、传感器、网关、消费产品及几乎其他任何电子设备编写强大而高效的应用程序 97 | 98 | SUN对Java语言的解释是:Java编程语言是个简单、面向对象、分布式、解释性、健壮、安全与系统无关、可移植、高性能、多线程和动态的语言 99 | 100 | 101 | ## 语言的特点 102 | 103 | - 1、__简单__
104 | Java语言的语法与C和C++语言很接近,使得大多数程序员很容易学习和使用Java。另一方面,Java丢弃了C++ 中很少使用的、很难理解的、令人迷惑的那些特性,如操作符重载、多继承、自动的强制类型转换。特别地,__Java语言不使用指针,并提供了自动的垃圾回收机制,使得程序员不必为内存管理而担忧__。 105 | 106 | - 2、__面向对象__
107 | Java语言提供类、接口和继承等原语,为了简单起见,只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制(关键字为implements)。Java语言全面支持动态绑定,而C++ 语言只对虚函数使用动态绑定。总之,Java语言是一个纯的面向对象程序设计语言。 108 | 109 | 面向对象是程序设计方法的一种。“面向对象程序设计语言”的核心之一就是开发者在设计软件的时候可以使用自定义的类型和关联操作。__代码和数据的实际集合体叫做“对象”__。一个对象可以想象成绑定了很多“行为(代码)”和“状态(数据)”的物体。对于数据结构的改变需要和代码进行通信然后操作,反之亦然。面向对象设计让大型软件工程的计划和设计变得更容易管理,能增强工程的健康度,减少失败工程的数量。 110 | 111 | - 3、__分布式__
112 | Java语言支持Internet应用的开发,在基本的Java应用编程接口中有一个网络应用编程接口(java.net),它提供了用于网络应用编程的类库,包括URL、URLConnection、Socket、 ServerSocket等。Java的RMI(远程方法激活)机制也是开发分布式应用的重要手段。 113 | 114 | - 4、__健壮__
115 | Java的强类型机制、异常处理、自动垃圾回收等是Java程序健壮性的重要保证。对指针的丢弃是Java的明智选择。Java的安全检查机制使得Java更具健壮性。 116 | 117 | - 5、__安全__
118 | Java通常被用在网络环境中,为此,Java提供了一个安全机制以防恶意代码的攻击。除了Java语言具有的许多安全特性以外,Java对通过网络下载的类具有一个安全防范机制(类ClassLoader),并提供安全管理机制(类SecurityManager)让Java应用设置安全哨兵。 119 | 120 | - 6、__体系结构中立__
121 | Java程序(后缀为java的文件)在Java平台上被编译为体系结构中立的字节码格式(后缀为class的文件), 然后可以在实现这个Java平台的任何系统中运行。这种途径适合于异构的网络环境和软件的分发。 122 | 123 | - 7、__可移植__
124 | 这种可移植性来源于体系结构中立性,另外,Java还严格规定了各个基本数据类型的长度。Java系统本身也具有很强的可移植性,Java编译器是用Java实现的,Java的运行环境是用ANSI C实现的。 125 | 126 | - 8、__解释型__
127 | 如前所述,Java程序在Java平台上被编译为字节码格式, 然后可以在实现这个Java平台的任何系统中运行。在运行时,Java平台中的Java解释器对这些字节码进行解释执行,执行过程中需要的类在联接阶段被载入到运行环境中。 128 | 129 | - 9、__高性能__
130 | 与那些解释型的高级脚本语言相比,Java的确是高性能的。事实上,Java的运行速度随着JIT(Just-In-Time)编译器技术的发展越来越接近于C++。 131 | 132 | - 10、__多线程__
133 | 在Java语言中,线程是一种特殊的对象,它必须由Thread类或其子(孙)类来创建。通常有两种方法来创建线程:其一,使用型构为Thread(Runnable)的构造子将一个实现了Runnable接口的对象包装成一个线程,其二,从Thread类派生出子类并重写run方法,使用该子类创建的对象即为线程。值得注意的是Thread类已经实现了Runnable接口,因此,任何一个线程均有它的run方法,而run方法中包含了线程所要运行的代码。线程的活动由一组方法来控制。Java语言支持多个线程的同时执行,并提供多线程之间的同步机制(关键字为synchronized)。 134 | 135 | - 11、__动态__
136 | Java语言的设计目标之一是适应于动态变化的环境。Java程序需要的类能够动态地被载入到运行环境,也可以通过网络来载入所需要的类。这也有利于软件的升级。另外,Java中的类有一个运行时刻的表示,能进行运行时刻的类型检查。 137 | 138 | 139 | 140 | ## 学习过程 141 | 142 | ![](fig/LearningJAVA.png) 143 | 144 | ## 与C/C++语言的异同 145 | 146 | ### 类似 147 | - Java编程语言的风格十分接近C++语言。 148 | - 继承了C++语言面向对象技术的核心, 149 | 150 | ### 区别 151 | - 舍弃了C++语言中容易引起错误的指针,改以引用取代, 152 | - 移除原C++与原来运算符重载,也移除多重继承特性,改用接口取代,增加垃圾回收器功能。 153 | 154 | 155 | 156 | ### 开发步骤 157 | #### Java程序开发步骤(编码,编译,解释,执行 ) 158 | Forward and Backward 159 | 160 | #### C/C++程序开发步骤(编码,编译,执行 ) 161 | 162 | Forward and Backward 163 | 164 | ## 运行环境与开发环境 165 | 166 | Forward and Backward 167 | 168 | 169 | ### JRE(Java Runtime Environment) 170 | 如果只想运行别人的Java程序可以只安装Java运行环境(Java Runtime Environment,JRE), 171 | JRE由Java虚拟机(Java Virtual Machine,JVM)、Java的核心类、以及一些支持文件组成。 172 | 173 | 不包含开发工具(JDK)--编译器、调试器和其它工具。 174 | 175 | 176 | ### Java Virtual Machine(JVM) 177 | - Java虚拟机 178 | - Java的核心和基础,在java编译器和os平台之间的虚拟处理器。 179 | - 是一种基于下层的操作系统和硬件平台并利用软件方法来实现的抽象的计算机,可以在上面执行Java的字节码程序。 180 | - 不同的操作系统有不同的虚拟机。 181 | 182 | Forward and Backward 183 | 184 | - Java编译器只需面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译器,编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。 185 | 186 | - JVM是Java程序运行的容器,但是他同时也是操作系统的一个进程,因此他也有他自己的运行的生命周期,也有自己的代码和数据空间。 187 | 188 | Forward and Backward 189 | 190 | 191 | #### Java字节代码运行的两种方式: 192 | 193 | - Interpreter(解释方式) 194 | 195 | - Just-in-time(即时编译):有代码生成器将字节代码转换成本机的机器代码,然后可以以较高速度执行. 196 | 197 | #### 任务 198 | 199 | - 提供垃圾回收功能 200 | - 提供运行时环境 201 | - 提供中立的体系结构 202 | 203 | 204 | --- 205 | 206 | ### JDK(Java Development Kit) 207 | 208 | JDK(Java Development Kit)是Java语言的软件开发工具包(SDK)。 209 | 210 | Forward and Backward 211 | 212 | ##### SE(J2SE), 213 | 214 | - Standard Edition,标准版,是我们通常用的一个版本,从JDK 5.0开始,改名为Java SE。
215 | 216 | - J2SE(Java 2 Standard Edition),商业版本,包含那些构成Java语言核心的类,定位在客户端,主要用于桌面应用的编程; 217 | 218 | ##### EE(J2EE), 219 | 220 | - Enterprise Edition,企业版,使用这种JDK开发J2EE应用程序,从JDK 5.0开始,改名为Java EE。
221 | - J2EE(Java 2 Platform Enterprise Edition),平台企业版,是一套全然不同于传统应用开发的技术架构,核心是一组技术规范与指南; 222 | 223 | ##### ME(J2ME), 224 | 225 | - Micro Edition,主要用于移动设备、嵌入式设备上的java应用程序,从JDK 5.0开始,改名为Java ME。
226 | - J2ME(Java 2 Platform Micro Edition),嵌入式设备及消费类电器版,又称为Java 2 微型版。 227 | 228 | 没有JDK的话,无法编译Java程序,如果想只运行Java程序,要确保已安装相应的JRE。 229 | 230 | 231 | #### JDK的基本组件包括: 232 | 233 | - javac – 编译器,将源程序转成字节码 234 | - jar – 打包工具,将相关的类文件打包成一个文件 235 | - javadoc – 文档生成器,从源码注释中提取文档 236 | - jdb – debugger,查错工具 237 | - java – 运行编译后的java程序(.class后缀的) 238 | - appletviewer:小程序浏览器,一种执行HTML文件上的Java小程序的Java浏览器。 239 | - Javah:产生可以调用Java过程的C过程,或建立能被Java程序调用的C过程的头文件。 240 | - Javap:Java反汇编器,显示编译类文件中的可访问功能和数据,同时显示字节代码含义。 241 | - Jconsole: Java进行系统调试和监控的工具 242 | 243 | 244 | 245 | #### 常用的包 246 | - java.lang: 这个是系统的基础类,比如String等都是这里面的,这个包是唯一一个可以不用引入(import)就可以使用的包。 247 | - java.io: 这里面是所有输入输出有关的类,比如文件操作等。 248 | - java.nio:为了完善io包中的功能,提高io包中性能而写的一个新包 ,例如NIO非堵塞应用 249 | - java.net: 这里面是与网络有关的类,比如URL,URLConnection等。 250 | - java.util: 这个是系统辅助类,特别是集合类Collection,List,Map等。 251 | - java.sql: 这个是数据库操作的类,Connection, Statement,ResultSet等。 252 | - javax.servlet:这个是JSP,Servlet等使用到的类。 253 | 254 | 255 | ###有关Java的专业术语 256 | 257 | - **Server JRE (Java SE Runtime Environment)**:服务端使用的 Java 运行环境 258 | - **SDK(Software Development Kit)**:软件开发工具包,在Java中用于描述1998年~2006年之间的JDK 259 | - **DAO(Data Access Object)**:数据访问接口,数据访问,顾名思义就是与数据库打交道 260 | - **MVC(Model View Controller)**:模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用于组织代码用一种业务逻辑和数据显示分离的方法 261 | 262 | 263 | - **JRE** 与 **Server JRE** 区别: 264 | 265 | Software Developers: JDK (Java SE Development Kit). For Java Developers. Includes a complete JRE plus tools for developing, debugging, and monitoring Java applications. 266 | Administrators running applications on a server: Server JRE (Server Java Runtime Environment) For deploying Java applications on servers. Includes tools for JVM monitoring and tools commonly required for server applications, but does not include browser integration (the Java plug-in), auto-update, nor an installer. 267 | 268 | --- 269 | 270 | ### Eclipse 271 | 272 | 一款非常受欢迎的Java开发工具,用它开发Java的人员是最多的。 273 | 274 | 275 | - Eclipse是一种可扩展的跨平台开源集成开发环境(IDE)。 276 | 277 | - 最初主要用来Java语言开发,目前亦有人通过插件使其作为C++、Python、PHP等其他语言的开发工具。 278 | 279 | - 历史:
280 | 2001年11月,IBM公司捐出价值4,000万美元的源代码组建了Eclipse联盟,并由该联盟负责这种工具的后续开发。集成开发环境(IDE)经常将其应用范围限定在“开发、构建和调试”的周期之中。为了帮助集成开发环境(IDE)克服目前的局限性,业界厂商合作创建了Eclipse平台。Eclipse允许在同一IDE中集成来自不同供应商的工具,并实现了工具之间的互操作性,从而显著改变了项目工作流程,使开发者可以专注在实际的嵌入式目标上。 281 | - 特点:
282 | 能接受由Java开发者自己编写的开放源代码插件,这类似于微软公司的Visual Studio和Sun公司的NetBeans平台。 283 | Eclipse为工具开发商提供了更好的灵活性,使他们能更好地控制自己的软件技术。 284 | 285 | 286 | 287 | ### Java程序分成三类: 288 | 289 | - Application(应用程序) 290 | - Applet(小应用程序) 291 | - 特定的程序 292 | 293 | #### Java Application(应用程序) 294 | 295 | - 独立的Java程序 296 | 297 | - 在计算机中单独运行 298 | 299 | - 程序入口方法: 300 | 301 | ~~~java 302 | public static void main(String[] args) { 303 | … 304 | } 305 | ~~~ 306 | 307 | #### 小应用程序-Java Applet 308 | 309 | - 嵌在HTML网页中运行 310 | - 特定标记 311 | 312 | ~~~xml 313 | 314 | ~~~ 315 | - 在Web浏览器中运行(内嵌Java虚拟机) 316 | 317 | #### 特定的程序 318 | 319 | Servlet(服务器端小程序),EJB等 320 | Servlet是运行在服务器端的小程序,它可以处理客户传来的请求(request),然后传给客户端(response)。 321 | 322 | 323 | 324 | ## “Hello Word!"程序 325 | 326 | ~~~java 327 | public class HelloWorld { 328 | 329 | public static void main(String[] args) { 330 | 331 | System.out.println("Hello, World!"); 332 | } 333 | } 334 | ~~~ 335 | 336 | ### main方法(main Method) 337 | 每个Java应用程序==必须有且只能有的一个main方法,它是程序执行的入口,运行时被虚拟机自动执行== 338 | 339 | #### main方法的声明格式是固定的, 340 | - main方法必须声明为public 341 | - main的参数必须为String对象的数组 342 | - main方法必须为static 343 | 344 | #### 类的名字必须和文件名相同。 345 | 346 | #### 文件中必须存在某个类与该文件同名, 347 | - 且这个类必须包含一个名为__main()__的方法 348 | 349 | ### Return关键字: 350 | 351 | - 1、代表“已经做完,离开此方法”; 352 | - 2、如果此方法产生了一个值,这个值要放在return语句后面。 353 | 354 | 如果不想返回值,可以指示此方法返回void(空)。 355 | 356 | ### static关键字 357 | 当声明一个事物是static时,就意味着这个域或方法不会与包含它的那个类的任何对象实例关联在一起。 358 | 因此,即使从未创建某个类的任何对象,也可以调用其static方法或访问其static域。 359 | 只须将static关键字放在定义之前,就可以将字段或方法设定为static。 360 | 361 | #### 引用static方法: 362 | 363 | - 1、通过对象引用; 364 | - 2、通过类名直接引用。 365 | 366 | static 方法的一个重要用法是:__在不创建任何对象的前提下就可以调用它。__ 367 | 这一特点对定义main()方法很重要,这个方法是运行一个应用时的入口点。 368 | 369 | 370 | #### 引用static变量的方法与引用static方法相似 371 | 372 | - 1、通过对象引用; 373 | - 2、通过类名直接引用。 374 | 375 | 使用类名引用static变量是首选方式,不仅强调了变量的static结构,而且还为编译器优化提供了机会。 376 | 377 | 378 | ### 常犯的错误 379 | 380 | - 声明一个类的关键字__class__,写成了__Class__,要注意大小写。 381 | 382 | - 声明main方法时,方法修饰符没有严格按照__public static void__的顺序, 并且其参数是一个字符串数组__String[]__ 383 | 384 | - 大小写问题,例如把main方法的参数args的类型String[],改成了string[],把System写成了system。 385 | >'JAVAC' is not recognized as an internal or external command,operable program or batch file. 386 | 387 | 解释:编译错误。包含javac.exe编译器的路径变量设置不正确,操作系统无法发现该执行文件。 388 | 389 | - 类名和文件名不能保持一致。如: 390 | >HelloWorldApp.java:5: class HelloWorldApp is public, should be declared in a file named HelloWorldApp.java 391 | > public class HelloWorldApp{ 392 | 393 | 解释: 编译错误。当一个类被“public”修饰时,包含这个类的文件名应该和该类名完全一致。 394 | 395 | - 不能发现需要执行的类。如: 396 | > Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorldApp
397 | 398 | 解释:运行错误。有时即使该类的字节码文件就在当前目录下,也会报这种错误。这种错误的主要原因是由于没有为运行时环境提供正确的类加载说明,详细说明请参阅附录。 399 | 400 | 401 | ### 编码风格: 402 | 403 | - 类名的首字母要大写。 404 | 405 | - 如果类名由几个单词构成,那么把它们并在一起,其中每个内部单词的首字母都大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如MyFirstJavaClass。(驼峰风格) 406 | 407 | - 变量、方法以及对象引用名称等,编码风格与类风格类似,只是标识符的第一个字母采用小写。如果方法名含有若干单词,则后面的每个单词首字母大写,例如myFirstJavaMethod。 408 | 409 | - 源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记Java是大小写敏感的),文件名的后缀为.java。(如果文件名和类名不相同则会导致编译错误)。 410 | 411 | - 所有的Java程序由public static void main(String[] args)方法开始执行。 412 | 413 | - 注意:
414 | public修饰的类名称必须与包含它的Java源程序文件名一致
415 | 416 | 大小写敏感:Java是大小写敏感的,这就意味着标识符Hello与hello是不同的。 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | ## 参考资料 425 | 426 | ### 书籍 427 | - Thinking in Java 428 | - Java参考大全J2SE 429 | - Core Java 2 430 | 431 | - JDK1.7版的Java核心API文档 432 | 433 | 434 | 435 | ### 程序员的必备站点 436 | - 437 | - 438 | - 知乎 439 | - 简书 440 | 441 | ### 搜索引擎 442 | - Google 443 | - Baidu 444 | - bing 445 | 446 | ### Java技术论坛 447 | - 448 | - 449 | - 450 | - 451 | 452 | 453 | 458 | 459 | 460 | # 练习 461 | 462 | ## 请简要说明如下名词的含意: 463 | 464 | - JRE 465 | - JDK 466 | - JVM 467 | - J2EE 468 | - 469 | 470 | --- 471 | 472 | 本文档 Github : 473 | https://github.com/bushehui/Java_tutorial 474 | 475 | 478 | 479 | 482 | 483 | -------------------------------------------------------------------------------- /ch10.md: -------------------------------------------------------------------------------- 1 | --- 2 | title : 网络编程和通信 3 | --- 4 | 5 | [TOC] 6 | 7 | # 网络编程和通信 8 | 9 | ## 网络 10 | 11 | ### TCP/IP协议 12 | 13 | TCP/IP协议(传输控制协议)由网络层的IP协议和传输层的TCP协议组成。IP层负责网络主机的定位,数据传输的路由,由IP地址可以唯一的确定Internet上的一台主机。TCP层负责面向应用的可靠的或非可靠的数据传输机制,这是网络编程的主要对象。 14 | 15 | ### 端口 16 | 17 | Internet上传输的数据都带有标识目的主机与端口号的地址信息,主机的地址由$32$位的IP地址标识,IP协议通过该地址把数据发送到正确的目的主机; 18 | 端口号由一个$16$位的数字标识,TCP与UDP协议根据端口号把数据传送给正确的应用程序。 19 | 20 | 端口号的范围是$0~65535$,其中$1~1023$之间的端口号是为HTTP、FTP等系统应用保留的,FTP协议的端口号是$21$,HTTP协议的端口号是$80$,Telnet协议的端口号是$23$,用户应用程序只能使用$1024$以上的端口号,其中$1024~4999$可任意被用户用作客户端套接字端口,$5000~65535$可任意被用户用作服务端套接字端口。 21 | 22 | 23 | ## Java提供的网络功能 24 | 25 | 针对网络通信的不同层次,Java提供的网络功能有四大类:InetAddress 、URLs、Sockets、Datagram。 26 | 27 | - InetAddress: 28 | 面向IP层,用于标识网络上的硬件资源。 29 | 30 | - URL和URLConnection: 31 | 面向应用层,通过URL,Java程序可以直接送出或读入网络上的数据。 32 | 33 | - Sockets 34 | - 面向传输层。 35 | - Datagram则使用UDP协议,是另一种网络传输方式,它把数据的目的地纪录在数据包中,然后直接放在网络上。 36 | 37 | - Datagram: 38 | - 面向传输层。 39 | - Sockets使用的是TCP协议,这是传统网络程序最常用的方式,可以想象为两个不同的程序通过网络的通信信道进行通信。 40 | 41 | 42 | ### java.net包中的主要的类 43 | 44 | - 面向IP层的类:InetAddress 45 | 46 | - 面向应用层的类:URL、URLConnection 47 | 48 | - 面向传输层的类: 49 | - TCP协议相关类:Socket、ServerSocket 50 | - UDP协议相关类:DatagramPacket、DatagramSocket、 MulticastSocket 51 | 52 | ### 可能产生的异常: 53 | 54 | - BindException、 55 | - ConnectException、 56 | - MalformedURLException、 57 | - NoRouteToHostException、 58 | - ProtocolException、 59 | - SocketException、 60 | - UnknownHostException、 61 | - UnknownServiceException 62 | 63 | 64 | ## Socket通信 65 | 66 | ### Socket 67 | 68 | Socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。网络上的两个程序通过一个双向的通讯连接实现数据的交换,这个双向链路的一端称为一个Socket,一个Socket由一个IP地址和一个端口号唯一确定。应用程序通常通过"套接字"向网络发出请求或者应答网络请求。 Socket是TCP/IP协议的一个十分流行的编程界面,但是,Socket所支持的协议种类也不光TCP/IP一种,因此两者之间是没有必然联系的。在Java环境下,Socket编程主要是指基于TCP/IP协议的网络编程。 69 | 70 | **Socket通讯过程**: 71 | 服务端监听某个端口是否有连接请求,客户端向服务端发送连接请求,服务端收到连接请求向客户端发出接收消息,这样一个连接就建立起来了。客户端和服务端都可以相互发送消息与对方进行通讯。 72 | 73 | Socket的基本工作过程包含以下四个步骤: 74 | 75 | 1. 创建Socket; 76 | 2. 打开连接到Socket的输入输出流; 77 | 3. 按照一定的协议对Socket进行读写操作; 78 | 4. 关闭Socket。 79 | 80 | 81 | ### Socket通信机制 82 | 83 | 提供了两种通信方式: 84 | 85 | - 有连接方式(TCP) 86 | 有连接方式中,通信双方在开始时必须进行一次连接过程,建立一条通信链路。通信链路提供了可靠的、全双工的字节流服务。 87 | 88 | 通过TCP协议传输,得到的是一个顺序的无差错的数据流。发送方和接收方的成对的两个socket之间必须建立连接,以便在TCP协议的基础上进行通信,当一个socket(通常都是server socket)等待建立连接时,另一个socket可以要求进行连接,一旦这两个socket连接起来,它们就可以进行双向数据传输,双方都可以进行发送或接收操作。 89 | 90 | 91 | - 无连接方式(UDP数据报)。 92 | 无连接方式中,通信双方不存在一个连接过程,一次网络I/O以一个数据报形式进行,而且每次网络I/O可以和不同主机的不同进程进行。无连接方式开销小于有连接方式,但是所提供的数据传输服务不可靠,不能保证数据报一定到达目的地。 93 | 94 | 每个数据报都是一个独立的信息,包括完整的源地址或目的地址,它在网络上以任何可能的路径传往目的地,因此能否到达目的地,到达目的地的时间以及内容的正确性都是不能被保证的。 95 | 96 | 97 | 98 | Java语言同时支持有连接和数据报通信方式,在这两种方式中都采用了Socket表示通信过程中的端点。 99 | 100 | 101 | 102 | #### TCP与UDP区别: 103 | 104 | ##### TCP特点: 105 | 106 | 1、TCP是面向连接的协议,通过三次握手建立连接,通讯完成时要拆除连接,由于TCP是面向连接协议,所以只能用于点对点的通讯。而且建立连接也需要消耗时间和开销。 107 | 108 | 2、TCP传输数据无大小限制,进行大数据传输。 109 | 110 | 3、TCP是一个可靠的协议,它能保证接收方能够完整正确地接收到发送方发送的全部数据。 111 | 112 | ##### UDP特点: 113 | 114 |   1、UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送。 115 | 116 |   2、UDP传输数据时有大小限制,每个被传输的数据报必须限定在64KB之内。 117 | 118 |   3、UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。 119 | 120 | #### TCP与UDP应用: 121 | 122 | 1、TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。但是可靠的传输是要付出代价的,对数据内容正确性的检验必然占用计算机的处理时间和网络的带宽,因此TCP传输的效率不如UDP高。 123 | 124 | 2,UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序。例如视频会议系统,并不要求音频视频数据绝对的正确,只要保证连贯性就可以了,这种情况下显然使用UDP会更合理一些。 125 | 126 | 127 | ### Socket通信 128 | 129 | - 端到端的连接与通信 130 | - 网络上的两个程序(进程)通过一个双向的通信连接实现数据的交换。 131 | - 双向链路的一端称为一个socket(套接字) 132 | - 主机—端口(用于区分同一台主机上的不同的通信应用进程:0~1023系统 1024~65535用户) 133 | 134 | 135 | 136 | 137 | ### Socket通信过程 138 | 139 | 服务器端的程序首先选择一个端口(port)注册,然后调用accept()方法对此端口进行监听,即等待其它程序的连接申请。如果客户端的程序申请和此端口连接,那么服务器端就利用accept()方法来取得这个连接的Socket。 140 | 141 | 客户端的程序建立Socket时必须指定服务器的地址(host)和通信的端口(port),这个端口必须与服务器端监听的端口保持一致。 142 | 143 | 144 | ## URL通信 145 | 146 | URL(Uniform Resource Locator):统一资源定位器,它表示Internet/Intranet上一个资源的引用或地址,这些资源可以是一个文件、一个目录或一个对象。 147 | 148 | URL是由一个字符串来描述的,URL包括协议和资源名称两部分,协议表示访问资源所需的协议,如HTTP、FTP等;资源名称表示要访问的资源地址。 149 | 150 | ### InetAddress类 151 | 152 | InetAddress类是IP地址的封装类,描述了32位或128位IP地址。InetAddress类含有IP地址和域名,借助于这个类,既可以通过主机域名获得IP地址,也可通过主机IP地址获得域名。 153 | 154 | InetAddress类没有构造函数,因此不能用new来构造一个InetAddress实例。通常是用它提供的静态方法来获取: 155 | public static InetAddress getByName(String host) :host可以是一个机器名,也可以是一个形如“%d.%d.%d.%d”的IP地址或一个DSN域名。 156 | public static InetAddress getLocalHost() 157 | public static InetAddress[] getAllByName(String host) 158 | 这三个方法会产生UnknownHostException异常,应在程序中捕获处理。 159 | 160 | InetAddress类的几个主要方法: 161 | String getHostName():获取InetAddress对象所含的域名 162 | getHostAddress():获取InetAddress对象所含的IP地址 163 | 164 | ### URL类 165 | 166 | #### URL类的构造方法 167 | (1) public URL(String spec) 168 | (2) public URL(String protocol, String host, String file) 169 | (3) public URL(String protocol,String host,String port,String file) 170 | (4) public URL(URL context,String spec) 171 | 注意:类URL的构造方法都声明抛出非运行时异常(MalformedURLException),因此生成URL对象时,我们必须要对这一异常进行处理,用try-catch语句进行捕获。 172 | 173 | #### URL类的成员方法 174 | |成员方法|功能说明| 175 | |:---:|:---| 176 | |public int getPort()|获取端口号。若端口号未设置,返回–1| 177 | |public String getProtocol()|获取协议名。若协议未设置,返回null| 178 | |public String getHost()|获取主机名。若主机名未设置,返回null| 179 | |public String getFile()|获取文件名。若文件名未设置,返回null| 180 | |public boolean equals(Object obj)|与指定的URL对象obj进行比较,如果相同返回true,否则返回false| 181 | |public final InputStream openStream()|获取输入流。若获取失败,则抛出一个java.io.Exception异常。| 182 | |public URLConnection openConnection()|生成关联该URL的一个URLConnection对象| 183 | |String toString()|将此URL对象转换成字符串形式| 184 | 185 | ### URLConnection类 186 | 187 | 通过URLConnection类,可以在应用程序和URL资源之间进行交互,既可以从URL中读取数据,也可以向URL中发送数据。URLConnection类表示了应用程序和URL资源之间的通信连接。 188 | 189 | 1.创建URLConnection类的对象 190 | URLConnection类是一个抽象类,创建URLConnection对象分两步完成:创建一个URL对象,然后调用该URL对象的openConnection()方法返回一个对应其URL地址的URLConnection对象。 191 | 192 | 2.向服务器端写数据 193 | 首先建立输出数据流: 194 | PrintStream out=new PrintStream(con.getOutputStream()); 195 | 然后向服务器写入信息: 196 | out.println(String data); 197 | 198 | 3.从服务器端读数据 199 | 建立输入数据流: 200 | InputStreamReader ins=new InputStreamReader(con.getInputStream()); 201 | BufferedReader in=new BufferedReader(ins); 202 | 或: 203 | DataInputStream dis=new DataInputStream(con.getInputStream()); 204 | 然后从服务器读信息: 205 | in.readLine(); 或:is.readLine(); 206 | 207 | ### TCP Socket通信 208 | 209 | TCP(Transport Control Protocol) 210 | 两主机之间有连接的、可靠的、端对端(end-to-end)的数据流的传输 211 | 如http, ftp, telnet 的传输层均使用此协议 212 | 213 | 为了支持TCP/IP面向连接的网络程序的开发,java.net包提供了Socket类与ServerSocket类,ServerSocket类和Socket类均直接继承于Java的Object根类。 214 | 其中,ServerSocket类用于服务端程序,它有一个accept方法专门用来监听客户端的连接,并产生一个与客户端连接相对应的Socket对象; 215 | Socket类则是服务端程序和客户端程序都要用到的类,该类专门用来处理连接双方的数据通信。 216 | 一个Socket由一个IP地址和一个端口号唯一确定。 217 | 218 | #### URL通信与Socket通信的区别 219 | 220 | URL通信与Socket通信都是面向连接的通信。区别在于: 221 | 222 | - (1)Socket通信方式为主动等待客户端的服务请求方式,而URL通信方式为被动等待客户端的服务请求方式。 223 | 224 | - (2)利用Socket进行通信时,在服务器端运行了一个Socket通信程序,不停地监听客户端的连接请求,当接到客户端请求后,马上建立连接并进行通信。利用URL进行通信时,在服务器端常驻一个CGI程序,但它一直处于睡眠状态,只有当客户端的连接请求到达时才被唤醒,然后建立连接并进行通信。 225 | 226 | - (3)在Socket通信方式中,服务器端的程序可以打开多个线程与多个客户端进行通信,并且还可以通过服务器使各个客户端之间进行通信,这种方式适合于一些较复杂的通信。而在URL通信方式中,服务器端的程序只能与一个客户进行通信,这种方式比较适合于B/S通信模式。 227 | 228 | #### 使用Socket通信过程 229 | 230 | 利用socket进行有连接的通信过程包括以下三个步骤: 231 | 232 | - (1) 创建socket,建立连接 233 | java.net包中的两个类Socket与ServerSocket分别表示连接的Client端和Server端,进行网络通信的方法也都封装在这两个类中。建立连接首先要创建这两个类的对象并把它们关联起来。 234 | 235 | - (2) 打开连接到Socket的输入输出流,按照一定的协议对Socket进行读写操作 236 | 连接建立后,要进一步获取连接上的I/O流,并通过这些流进行数据传输。 237 | 238 | - (3) 关闭Socket 239 | 240 | 241 | #### Socket类 242 | 243 | ##### 构造方法: 244 | 245 | |构造方法|功能说明| 246 | |:---|:---| 247 | |public Socket(InetAddress address,int port)|使用InetAddress对象所表示的IP地址以及端口号(port)向服务器发起连接,若成功则创建Socket对象,否则抛出异常| 248 | |public Socket(InetAddress address,int port, boolean stream)|同上,若布尔参数为true,则采用流式通信方式,否则为数据报通信方式| 249 | |public Socket(String host,int port)|使用指定端口port和主机host,向服务器发起连接,若成功则创建Socket对象,否则抛出异常| 250 | |public Socket(String host,int port,Boolean stream)|同上,布尔参数为true,则采用流式通信方式| 251 | 252 | ##### 常用成员方法 253 | 254 | |常用成员方法|功能说明| 255 | |:---|:---| 256 | |public void close()|关闭Socket,释放资源| 257 | |public InputStream getInputStream()|获取与Socket相关联的字节输入流,用于从Socket中读数据| 258 | |public OutputStream getOutputStream()|获取与Socket相关联的字节输出流,用于向Socket中写数据| 259 | |public int getLocalPort()|返回本地Socket中的端口号| 260 | |public int getPort()|返回对方Socket中的端口号| 261 | |public InetAddress getLocalAddress()|返回本地Socket中IP的InetAddress对象| 262 | |public InetAddress getInetAddress()|返回对方Socket中IP的InetAddress对象| 263 | |public void setSoTimeout(int timeout)|设置客户端的连接超时时间。当程序调用Socket输入流对象的read方法读取数据后,程序将处于阻塞状态,直到setSoTimeout方法所设置的timeout时间超时为止。如果timeout为0,将表示read方法无限期地等待数据来读取| 264 | 265 | 266 | #### ServerSocket类 267 | 268 | ##### 构造方法: 269 | 270 | |构造方法|功能说明| 271 | |:---|:---| 272 | |public ServerSocket(int port) throws IOException|在指定的端口创建一个服务器Socket对象,默认可接收50个客户端连接。如果端口号设置为0,则自动挑选一个空闲的端口号。如果打开这个套接字时出现I/O错误,则抛出异常对象IOException| 273 | |public ServerSocket(int port,int count) throws IOException|在指定的端口port创建一个服务器 Socket对象,并说明服务器端所能支持的最大连接数count,如果超过此数目,客户端连接将被拒绝| 274 | |public ServerSocket(int port,int count, InetAddress bindArr) throws IOException|在指定的端口port创建一个服务器 Socket对象,并说明服务器端所能支持的最大连接数count,bindAddr可用来绑定服务器程序所使用的IP地址。如果运行服务端程序的机器配置了多个IP地址(多网卡),这个构造函数将非常有用| 275 | 276 | ##### 常用成员方法 277 | 278 | |常用成员方法|功能说明| 279 | |:---|:---| 280 | |public Socket accept() throws IOException|监听客户端的连接请求。accept方法调用后,服务器程序将处于阻塞状态,直到监听到客户端连接,返回一个新创建的Socket对象。接下来利用这个返回的Socket对象与客户端进行数据收发| 281 | |public void setSoTimeout(int timeout)|设置服务器程序等待客户端连接的最长时间timeout,时间单位为毫秒。如果timeout为0,将表示无限期等待客户端连接。该方法必须在accept方法之前被调用| 282 | |public void close() throws IOException|关闭套接字资源| 283 | 284 | 285 | ## 数据报通信 286 | 287 | 用户数据报协议UDP是传输层的无连接通信协议。数据报是一种在网络中独立传播的自身包含地址信息的消息,它能否到达目的地、到达的时间以及到达时内容能否保持不变,这些都是不能保证的。由于UDP通信速度较快,所以常常被应用在某些无须实时交互、准确性要求不高、但传输速度要求较高的场合。 288 | Java.net软件包中的DatagramSocket类和DatagramPacket类为实现UDP通信提供了支持。DatagramSocket用于在程序中间建立传送数据报的通信连接,DatagramPacket则用来表示一个数据报。 289 | 290 | #### 数据报方式的通信过程 291 | 292 | - (1) 创建数据报Socket; 293 | - (2) 构造用于接收或发送的数据报,并调用所创建Socket的receive()方法进行数据报接收或调用send()发送数据报。 294 | - (3)通信结束,关闭Socket。 295 | 296 | #### DatagramSocket类 297 | 298 | DatagramSocket类的三个构造方法如下: 299 | 300 | - (1) DatagramSocket():创建DatagramSocket对象并与本地主机某个可用端口相连。 301 | - (2) DatagramSocket(int port):创建DatagramSocket对象并与指定端口相连。 302 | - (3) DatagramSocket(int port,InetAddress iaddr):创建一个于本地地址绑定的DatagramSocket对象。 303 | 304 | ### 基于TCP的socket编程 305 | 306 | #### 服务器程序编写 307 | 308 | - ①调用ServerSocket(int port)创建一个服务器端套接字,并绑定到指定端口上; 309 | - ②调用accept(),监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字。 310 | - ③调用Socket类的getOutputStream()和getInputStream获取输出流和输入流,开始网络数据的发送和接收。 311 | - ④最后关闭通信套接字。 312 | 313 | #### 客户端程序编写: 314 | 315 | - ①调用Socket()创建一个流套接字,并连接到服务器端; 316 | - ②调用Socket类的getOutputStream()和getInputStream获取输出流和输入流,开始网络数据的发送和接收。 317 | - ③最后关闭通信套接字。 318 | 319 | 320 | 321 | 322 | ### TCP Socket Demo 323 | 下面给出一个客户端服务端 TCP 通信的 Demo,该客户端在 20006 端口请求与服务端建立 TCP 连接,客户端不断接收键盘输入,并将其发送到服务端,服务端在接收到的数据前面加上“echo”字符串,并将组合后的字符串发回给客户端,如此循环,直到客户端接收到键盘输入“bye”为止。 324 | 325 | #### 客户端代码如下: 326 | 327 | ~~~java 328 | package zyb.org.client; 329 | 330 | import java.io.BufferedReader; 331 | import java.io.IOException; 332 | import java.io.InputStreamReader; 333 | import java.io.PrintStream; 334 | import java.net.Socket; 335 | import java.net.SocketTimeoutException; 336 | 337 | public class Client1 { 338 | public static void main(String[] args) throws IOException { 339 | //客户端请求与本机在20006端口建立TCP连接 340 | Socket client = new Socket("127.0.0.1", 20006); 341 | client.setSoTimeout(10000); 342 | //获取键盘输入 343 | BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); 344 | //获取Socket的输出流,用来发送数据到服务端 345 | PrintStream out = new PrintStream(client.getOutputStream()); 346 | //获取Socket的输入流,用来接收从服务端发送过来的数据 347 | BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream())); 348 | boolean flag = true; 349 | while(flag){ 350 | System.out.print("输入信息:"); 351 | String str = input.readLine(); 352 | //发送数据到服务端 353 | out.println(str); 354 | if("bye".equals(str)){ 355 | flag = false; 356 | }else{ 357 | try{ 358 | //从服务器端接收数据有个时间限制(系统自设,也可以自己设置),超过了这个时间,便会抛出该异常 359 | String echo = buf.readLine(); 360 | System.out.println(echo); 361 | }catch(SocketTimeoutException e){ 362 | System.out.println("Time out, No response"); 363 | } 364 | } 365 | } 366 | input.close(); 367 | if(client != null){ 368 | //如果构造函数建立起了连接,则关闭套接字,如果没有建立起连接,自然不用关闭 369 | client.close(); //只关闭socket,其关联的输入输出流也会被关闭 370 | } 371 | } 372 | } 373 | ~~~ 374 | 375 | 服务端需要用到多线程,这里单独写了一个多线程类,代码如下: 376 | 377 | ~~~java 378 | package zyb.org.server; 379 | 380 | import java.io.BufferedReader; 381 | import java.io.InputStreamReader; 382 | import java.io.PrintStream; 383 | import java.net.Socket; 384 | 385 | /** 386 | * 该类为多线程类,用于服务端 387 | */ 388 | public class ServerThread implements Runnable { 389 | 390 | private Socket client = null; 391 | public ServerThread(Socket client){ 392 | this.client = client; 393 | } 394 | 395 | @Override 396 | public void run() { 397 | try{ 398 | //获取Socket的输出流,用来向客户端发送数据 399 | PrintStream out = new PrintStream(client.getOutputStream()); 400 | //获取Socket的输入流,用来接收从客户端发送过来的数据 401 | BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream())); 402 | boolean flag =true; 403 | while(flag){ 404 | //接收从客户端发送过来的数据 405 | String str = buf.readLine(); 406 | if(str == null || "".equals(str)){ 407 | flag = false; 408 | }else{ 409 | if("bye".equals(str)){ 410 | flag = false; 411 | }else{ 412 | //将接收到的字符串前面加上echo,发送到对应的客户端 413 | out.println("echo:" + str); 414 | } 415 | } 416 | } 417 | out.close(); 418 | client.close(); 419 | }catch(Exception e){ 420 | e.printStackTrace(); 421 | } 422 | } 423 | 424 | } 425 | ~~~ 426 | 427 | #### 服务端处理 TCP 连接请求的代码如下: 428 | 429 | ~~~java 430 | package zyb.org.server; 431 | 432 | import java.net.ServerSocket; 433 | import java.net.Socket; 434 | 435 | public class Server1 { 436 | public static void main(String[] args) throws Exception{ 437 | //服务端在20006端口监听客户端请求的TCP连接 438 | ServerSocket server = new ServerSocket(20006); 439 | Socket client = null; 440 | boolean f = true; 441 | while(f){ 442 | //等待客户端的连接,如果没有获取连接 443 | client = server.accept(); 444 | System.out.println("与客户端连接成功!"); 445 | //为每个客户端连接开启一个线程 446 | new Thread(new ServerThread(client)).start(); 447 | } 448 | server.close(); 449 | } 450 | } 451 | ~~~ 452 | 453 | 454 | ### 基于UDP的socket编程 455 | 456 | ##### 接收端程序编写: 457 | ①调用DatagramSocket(int port)创建一个数据报套接字,并绑定到指定端口上; 458 | ②调用DatagramPacket(byte[] buf, int length),建立一个字节数组以接收UDP包 。 459 | ③调用DatagramSocket类的receive(),接收UDP包。 460 | ④最后关闭数据报套接字。 461 | 462 | ##### 发送端程序编写: 463 | ①调用DatagramSocket()创建一个数据报套接字; 464 | ②调用DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port),建立要发送的UDP包。 465 | ③调用DatagramSocket类的send(),发送UDP包。 466 | ④最后关闭数据报套接字。 467 | 468 | 469 | ##### DatagramSocket类的常用方法如下: 470 | (1) void receive(DatagramPacket packet)throws IOException 471 | receive()方法将使程序中的线程一直处于阻塞状态,直到从当前socket中接收到信息时,将收到的信息存储在receive()方法的对象参数packet的存储机构中。 472 | (2) void send(DatagramPacket packet)throws IOException 473 | send()方法将其参数DatagramPacket对象packet中包含的数据报文发送到所指定的IP地址主机的指定端口。 474 | (3) void setSotimeout(int timeout) throws IOException 475 | 当程序调用DatagramSocket的receive方法以读取数据后,程序将处于阻塞状态,知道setSoTimeout方法所设置时间超时为止。 476 | (4) void close() 477 | 关闭数据报套接字,它不会抛出异常对象。 478 | 479 | #### DatagramPacket类 480 | 当DatagramSocket套接字创建后,就可以用它来发送和接收数据报了。数据报是一个DatagramPacket类的对象,创建时必须指明目的端的IP地址和端口号,这样发送到网络上的数据报才可以被网关路由。DatagramPacket类的构造方法,分别对应接收数据报和发送数据报: 481 | 482 | (1) public DatagramPacket(byte[] buf,int length) 483 | 创建接收length长度的数据报对象。其中buf为接收数据报的字节数组,length为读取的字节数,length必须小于等于buf.length。 484 | 485 | (2) public DatagramPacket(byte[]buf, int offset, int length, InetAddress address, int port) 486 | 这个构造方法用来创建发送数据报对象。其中,buf代表发送数据报的字节数组;length代表发送数据报的长度;address代表发送数据报的目的地址,即接收者的IP地址;port代表发送数据报的端口号。 487 | 488 | ##### DatagramPacket类的常用方法如下: 489 | (1) public InetAddress getAddress() 490 | 返回发出数据报或接收数据报的机器的IP地址。 491 | (2) public int getPort() 492 | 返回发出数据报或接收数据报的远程主机的端口号。 493 | (3) public void setAddress(InetAddress iaddr) 494 | 设置接收数据报的机器的IP地址。 495 | 496 | 497 | 498 | ### UDP Socket Demo 499 | 这里有一点需要注意:UDP 程序在 receive()方法处阻塞,直到收到一个数据报文或等待超时。由于 UDP 协议是不可靠协议,如果数据报在传输过程中发生丢失,那么程序将会一直阻塞在 receive()方法处,这样客户端将永远都接收不到服务器端发送回来的数据,但是又没有任何提示。为了避免这个问题,我们在客户端使用 DatagramSocket 类的 setSoTimeout()方法来制定 receive()方法的最长阻塞时间,并指定重发数据报的次数,如果每次阻塞都超时,并且重发次数达到了设置的上限,则关闭客户端。 500 | 501 | 下面给出一个客户端服务端 UDP 通信的 Demo(没有用多线程),该客户端在本地 9000 端口监听接收到的数据,并将字符串"Hello UDPserver"发送到本地服务器的 3000 端口,服务端在本地 3000 端口监听接收到的数据,如果接收到数据,则返回字符串"Hello UDPclient"到该客户端的 9000 端口。在客户端,由于程序可能会一直阻塞在 receive()方法处,因此这里我们在客户端用 DatagramSocket 实例的 setSoTimeout()方法来指定 receive()的最长阻塞时间,并设置重发数据的次数,如果最终依然没有接收到从服务端发送回来的数据,我们就关闭客户端。 502 | 503 | #### 客户端代码如下: 504 | 505 | ~~~java 506 | package zyb.org.UDP; 507 | 508 | import java.io.IOException; 509 | import java.io.InterruptedIOException; 510 | import java.net.DatagramPacket; 511 | import java.net.DatagramSocket; 512 | import java.net.InetAddress; 513 | 514 | public class UDPClient { 515 | private static final int TIMEOUT = 5000; //设置接收数据的超时时间 516 | private static final int MAXNUM = 5; //设置重发数据的最多次数 517 | public static void main(String args[])throws IOException{ 518 | String str_send = "Hello UDPserver"; 519 | byte[] buf = new byte[1024]; 520 | //客户端在9000端口监听接收到的数据 521 | DatagramSocket ds = new DatagramSocket(9000); 522 | InetAddress loc = InetAddress.getLocalHost(); 523 | //定义用来发送数据的DatagramPacket实例 524 | DatagramPacket dp_send= new DatagramPacket(str_send.getBytes(),str_send.length(),loc,3000); 525 | //定义用来接收数据的DatagramPacket实例 526 | DatagramPacket dp_receive = new DatagramPacket(buf, 1024); 527 | //数据发向本地3000端口 528 | ds.setSoTimeout(TIMEOUT); //设置接收数据时阻塞的最长时间 529 | int tries = 0; //重发数据的次数 530 | boolean receivedResponse = false; //是否接收到数据的标志位 531 | //直到接收到数据,或者重发次数达到预定值,则退出循环 532 | while(!receivedResponse && tries 643 | 644 | 645 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | -------------------------------------------------------------------------------- /ch12.md: -------------------------------------------------------------------------------- 1 | --- 2 | title : Review 3 | --- 4 | 5 | [TOC] 6 | 7 | # Java基础知识 8 | 9 | ## 基本概念 10 | 11 | ![](fig/Java-Mindmap/4120002-7e4a2b32bca3882e.png) 12 | 13 | ## 主要特征 14 | 15 | ![](fig/Java-Mindmap/4120002-a18a40fd0180afaa.png) 16 | 17 | ## 基本语法 18 | ![](fig/Java-Mindmap/4120002-bdb51e206ee9ca0d.png) 19 | 20 | ### 基本数据类型 21 | 22 | ![](fig/Java-Mindmap/4120002-5989238d90b80c55.png) 23 | 24 | ![](fig/Java-Mindmap/4120002-5aed0e7d50180e47.png) 25 | 26 | #### Number & Math 27 | ![](fig/Java-Mindmap/4120002-a0d0a03f1a1e1680.png) 28 | 29 | #### 数组 30 | ![](fig/Java-Mindmap/4120002-74dc7e59ddffda64.png) 31 | 32 | #### String 33 | ![](fig/Java-Mindmap/4120002-9ac51deef1e7516d.png) 34 | ![](fig/Java-Mindmap/4120002-d753ccedc0c8af92.png) 35 | 36 | 37 | 38 | ### 变量 39 | ![](fig/Java-Mindmap/4120002-764c12e8c74ab0dd.png) 40 | 41 | ### 运算符 42 | 43 | ![](fig/Java-Mindmap/4120002-d0d8cda0cc9ca07c.png) 44 | 45 | ![](fig/Java-Mindmap/4120002-be47d789929ec252.png) 46 | 47 | ### 分支语句 48 | ![](fig/Java-Mindmap/4120002-e8a41a869911f730.png) 49 | 50 | 51 | ### IO 52 | ![](fig/Java-Mindmap/4120002-4e4e2e7eaf3edea9.png) 53 | 54 | ### 异常处理 55 | ![](fig/Java-Mindmap/4120002-b03fb6e32e6d7ebb.png) 56 | 57 | 58 | ### 开发环境配置 59 | 60 | ![](fig/Java-Mindmap/4120002-e63eb183f6f860cf.png) 61 | 62 | 63 | 64 | ## 面向对象 65 | 66 | ### 三大特性 67 | ![](fig/Java-Mindmap/4120002-4f8abdf9fa7ef630.png) 68 | 69 | ### Java的对象 70 | ![](fig/Java-Mindmap/4120002-f506cbdca8593918.png) 71 | 72 | ![](fig/Java-Mindmap/4120002-8ed65d3657480ed0.png) 73 | 74 | ### 修饰符 75 | ![](fig/Java-Mindmap/4120002-d105e32dea0dc8f9.png) 76 | 77 | ### 序列化 78 | ![](fig/Java-Mindmap/4120002-f6fefc4f54458850.png) 79 | 80 | 81 | ### 范型 82 | ![](fig/Java-Mindmap/4120002-f8b7cdd3e8abf3e8.png) 83 | 84 | 85 | 86 | ## 多线程编程 87 | 88 | ![](fig/Java-Mindmap/4120002-d800586dfc967291.png) 89 | 90 | ## 基于Socket的网络编程 91 | 92 | ![](fig/Java-Mindmap/4120002-ee23f25321b04d79.png) 93 | 94 | 95 | --- 96 | 97 | 本文档 Github : 98 | https://github.com/bushehui/Java_tutorial 99 | 100 | 101 | 104 | 105 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /ch6.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Java语言package 3 | --- 4 | 5 | [TOC] 6 | 7 | #包(package) 8 | 9 | 包(package)是Java提供的文件(即公共类)的组织方式。
10 | 一个包对应一个文件夹,一个包中可以包括许多类文件。
11 | 包中还可以再有子包,称为包等级。 12 | 13 | ##包的作用有四个: 14 | 15 | - (1) 定位类:具有相似功能的类可以放置在同一个包中,这样可以很容易地查找定位类。 16 | - (2) 避免命名冲突:在开发由其他程序员共享的可复用类时,会发生命名冲突,可以把类放在不同包中,通过包名引用类可以避免命名冲突。 17 | - (3) 可以方便地分发软件。 18 | - (4) 控制类之间的访问 19 | 20 | 注意: 21 | 22 | - 包是一个类名空间,同一个包中的类和接口不能重名,不同包中的类可以重名。 23 | - 根据Java的命名规则,包名均为小写字母。 24 | - 类之间的访问控制是通过类修饰符来实现的,若类修饰符为__public__,则表明该类不仅可供同一包中的类访问,也可以被其他包中的类访问。 25 | - 若类无修饰符,则表明该类仅供同一包中的类访问。 26 | - Java的包等级和Windows的文件组织方式完全相同,只是表示方法不同。 27 | 28 | 29 | 30 | ##包的定义 31 | 32 | 包的定义就是将源程序文件中的接口和类纳入指定的包。 33 | 34 | 一般情况下,Java源程序由四部分组成: 35 | 36 | - (1) 一个包(package)定义语句(可选项)。其作用是将本源文件中的接口和类纳入指定包。
源文件中若有包说明语句,必须是第一个语句; 37 | - (2) 若干个(import)语句(可选项)。其作用是引入本源文件中所需要使用的包; 38 | - (3) 一个__public__的类声明。
在一个源文件中只能有一个__public__类; 39 | - (4) 若干个属于本包的类声明(可选)。 40 | 41 | 包的定义语句格式: 42 | 43 | >package 包名1[.包名2[.包名3…]]; 44 | 45 | - 创建包就是在当前文件夹下创建一个子文件夹,存放这个包中包含的所有类和接口的.class文件。 46 | - 语句中的符号“.”代表了目录分隔符,说明这个语句创建了两个文件夹。 47 | 48 | ==习惯上,包名都用小写字母。== 49 | 50 | Java规定,如果一个Java文件中有package语句,那么package语句必须写在Java源程序的第一行,该行前只能有空格和注释行。
51 | Package语句在每个Java源程序中只能有一条,一个类只能属于一个包。 52 | 53 | 例如: 54 | 55 | ~~~java 56 | package cn.edu.hebiace; 57 | ~~~ 58 | 59 | 定义了包,语句中的包名分隔符“.”相当于目录分隔符。
60 | 使用package语句指定一个源文件中的类属于一个特定的包。 61 | 62 | Java要求包名与文件系统的目录结构一一对应。
63 | 对于名为cn.edu.hebiace的包,必须创建一个如图所示的目录结构。 64 | 65 | ![](fig/packagedir.png) 66 | 67 | 若源文件中未使用package语句创建包,则该源文件中的接口和类位于Java的无名包中(无名包又称默认包,指当前目录),会把源文件中的类存储在当前目录(即存放Java源文件的目录)下。 68 | 69 | ==无名包中的类不能被其他包中的类引用和复用== 70 | 71 | 72 | ##设置类路径 73 | 74 | 包是一种组织代码的有效手段,包名指出了程序中需要使用的".class"文件的所在之处。
75 | 另一个能指明".class"文件所在的位置是环境变量CLASSPATH。 76 | 77 | 对于Java Application程序,还可以通过为Java解释器设置参数来指定类文件路径。 78 | 79 | 例如, 80 | 对于JDK中的Java解释器java.exe,有开关参数-classpath; 81 | 82 | 假设当需要解释执行的test.class文件不在当前目录而在e盘的TEMP目录下时,可以使用如下的命令行语句: 83 | 84 | >java -classpath e:\temp Test 85 | 86 | 来运行这个程序 87 | 88 | 89 | ##包的使用 90 | 91 | Java提供了丰富的标准类来帮助程序设计者更方便快捷地编写程序,这些标准类组成了类包,主要有: 92 | 93 | - java.lang 94 | - java.applet 95 | - java.io 96 | - java.net 97 | - java.util 98 | - java.awt 99 | - java.awt.image 100 | - java.awt.peer 101 | 102 | 使用Swing组件进行GUI设计,使用javax.swing包中的类 103 | 104 | ==除了java.lang之外,其余类包都不是java语言所必须的。==
105 | 若要使用,必须进行包的导入。 106 | 107 | 将类组织成包的目的是为了更好地利用包中的类。 108 | 通常一个类只能引用与它在同一个包中的类。 109 | 110 | 如果需要使用其它包中的public类,则可以使用如下的几种方法。 111 | 112 | - (1) 在引入的类前加包名
113 | 例如: 114 | 115 | ~~~java 116 | pack1.pack2.Format.format(23.4533,2); 117 | ~~~ 118 | 119 | - (2) 单类型导入(single-type-import)
120 | 例如上面的语句在程序开始处增加了: 121 | 122 | ~~~java 123 | import pack1.pack2.Format; 124 | ~~~ 125 | 126 | 语句之后,就可以直接写成: 127 | 128 | ~~~java 129 | Format.format(23.4533,2); 130 | ~~~ 131 | 132 | - (3) 按需类型导入(type-import-on-demand) 133 | 134 | ~~~java 135 | import pack1.pack2.*; 136 | ~~~ 137 | 138 | ##内部类和匿名类 139 | 140 | ###内部类 141 | 一个类被嵌套定义于另一个类中,称为内部类(Inner Classes)或内隐类,包含内部类的类称为外部类。 142 | 143 | 外部类与内部类的访问原则是: 144 | 145 | - 在外部类中,一般通过一个内部类的对象来访问内部类的成员变量或方法; 146 | - 在内部类中,可以直接访问外部类的所有成员变量和方法(包括静态成员变量和方法、实例成员变量和方法及私有成员变量和方法)。 147 | 148 | 内部类和其他常规类类似,有下列特征: 149 | 150 | - (1)Java将内部类作为外部类的一个成员,内部类可以调用包含它的外部类的成员变量和成员方法,所以不必把外部类的引用传递给内部类的构造方法。 151 | - (2)内部类的类名只能用在外部类和内部类自身中,内部类的类名不能与外部类的类名相同。当外部类引用内部类时,须给出完整的名称(外部类名.内部类名)。 152 | - (3)内部类只是用来支持其外部类的工作,编译后,它的名称形如“外部类名称$内部类名称.class”。 153 | - (4)内部类可以声明为public、protected或private,其意义与用在类的其他成员上相同。 154 | 155 | 和普通的类一样,内部类也可以有静态的。
156 | __static__型内部类只能访问外部类中的__static__成员。
157 | 若要访问非static成员,须先创建一个外部类对象,然后通过该对象进行访问。 158 | 159 | 160 | ###匿名类 161 | 162 | 有时在定义事件处理代码时,由于代码短小,不必再明确定义一个类,可使用匿名内部类。 163 | 164 | 匿名内部类是__final__(最终)类,非static类,匿名内部类将类的声明和创建类的实例一步完成。 165 | 166 | 主要应用在事件处理的代码编写中。 167 | 168 | ~~~java 169 | JButton jb = new JButton("Exit"); 170 | 171 | jb.addActionListener(new ActionListener() { 172 | public void actionPerformed(ActionEvent e) { 173 | System.exit(-1); 174 | } 175 | }; 176 | ~~~ 177 | 178 | 注意:在使用匿名内部类时,要记住以下几个原则: 179 | 180 | - (1)匿名内部类不能有构造方法; 181 | - (2)匿名内部类不能定义任何静态成员、方法和类。 182 | - (3)匿名内部类不能是__public__, __protected__, __private__, __static__。 183 | - (4)只能创建匿名内部类的一个实例。
184 | 一个匿名内部类一定是在__new__的后面,用其隐含实现一个接口或实现一个类。
185 | 因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。 186 |
内部类只能访问外部类的静态变量或静态方法。 187 | - (5)当在匿名类中用__this__时,这个__this__则指的是匿名类或内部类本身。
188 | 这时如果要使用外部类的方法和变量,则应该加上外部类的类名 189 | 190 | 191 | 192 | ##访问控制和类的封装性 193 | 194 | 对类的成员变量和成员方法而言,其应用范围可以通过施以一定的访问权限来限定。 195 | 196 | ![](fig/classright.png) 197 | 198 | 注意: 199 | 200 | - __private__修饰符只能用来修饰类的数据成员和成员方法,而不能用来修饰类。 201 | - 修饰符__private__、 __public__、 __protected__都不能用来修饰方法中的局部变量。 202 | 在大部分情况下,一个类的构造方法都是__public__的。 203 | 但是,如果不想创建类的实例,可以定义__private__构造方法。 204 | 205 | 206 | ###类的封装性 207 | 208 | 保证模块正确性的措施是由信息的隐藏性来实现的。 209 | 210 | 类包括成员变量和方法两部分。 211 | 212 | - 那些允许其他包程序访问和修改的成员变量和方法可以定义为__public__类型; 213 | - 只允许同一个包中的其他类,以及该类的子类访问和修改的成员变量可以定义为__protected__类型; 214 | - 不允许其他类(内部类除外)访问和修改的成员变量可以定义为__private__类型。 215 | 216 | 217 | --- 218 | 219 | 本文档 Github : 220 | https://github.com/bushehui/Java_tutorial 221 | 222 | 223 | 224 | 225 | 226 | 229 | 230 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | -------------------------------------------------------------------------------- /ch6_1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Java语言面向对象 3 | --- 4 | 5 | 6 | [TOC] 7 | 8 | # 类和对象 9 | 10 | ## 面向对象概述 11 | 12 | ### 面向过程编程: 13 | 14 | __Fortran__、__Basic__,__C__等面向过程的程序设计语言,是按流程化的思想来组织的。 15 | 16 | 在这些语言的设计思想中,==通常将存放基本数据类型的变量作为程序处理对象、以变量的赋值作为程序的基本操作、以变量值的改变作为程序运行的状态。== 17 | 18 | >过程式的程序 = 算法 + 数据 19 | 20 | 这种程序设计风格的缺点: 21 | 22 | - 数据抽象简单 23 | - 信息完全暴露 24 | - 算法复杂 25 | - 无法很好地描述客观世界 26 | 27 | 在程序设计过程中,==为了实现有限度的代码重用,公共代码被组织成为过程或函数。==
28 | 当需要代码重用时,调用已经组织好的过程或函数。 29 | 30 | ==在这种应用方式中,如果软件项目庞大,程序的调试和维护将变得异常困难。== 31 | 32 | 33 | ### 面向对象编程: 34 | 35 | 面向对象的程序设计思想是==将数据以及对于这些数据的操作,封装在了一个单独的数据结构中。== 36 | 37 | 这种模式更近似于现实世界,所有的__对象__都__同时__拥有__属性__以及__与这些属性相关的行为__。
38 | 对象之间的联系是通过__消息__来实现的,__消息__是请求对象执行某一处理或回答某些信息的要求。 39 | 40 | 某个对象在执行相应的处理时,可以通过传递消息请求其他对象完成某些处理工作或回答某些消息。 41 | 42 | 其他对象在执行所要求的处理活动时,同样可以通过传递消息和另外的对象联系。 43 | 44 | ==一个面向对象程序的执行,就是靠对象间传递消息来完成的。== 45 | 46 | >面向对象的程序 = 对象 + 消息 47 | 48 | 49 | 面向对象程序设计是一种程序设计方法,或者是一种程序设计规范,它使用__对象__、__类__、__继承__、__封装__、__消息__等基本概念来进行程序的设计。 50 | 51 | 从现实世界中客观存在的事物(即对象)出发来构造软件系统,并且在系统构造中尽可能运用人类的自然思维方式。 52 | 53 | 开发一个软件是为了解决某些问题,这些问题所涉及的业务范围称作该软件的问题域。 54 | 55 | 其应用领域不仅仅是软件,还有计算机体系结构和人工智能等。 56 | 57 | 58 | ## 面向对象的三大特点:封装, 继承, 多态 59 | 60 | <<<<<<< HEAD 61 | ![](fig/Java-Mindmap/4120002-4f8abdf9fa7ef630.png) 62 | 63 | ======= 64 | >>>>>>> b45f7ffc2e01e8847a854596423fd41090d73ca0 65 | ### 封装 66 | __封装__就是把对象的属性和和对这些属性的操作封装在一个单独的数据结构中,并尽可能隐蔽对象的内部细节,包含两个含义: 67 | 68 | - 把对象的全部属性和对属性的全部操作结合在一起,形成一个不可分割的独立单元(即对象)。 69 | - 信息隐蔽,即尽可能隐蔽对象的内部细节,对外形成一个边界(或者说形成一道屏障),只保留有限的对外接口使之与外部发生联系。 70 | 71 | 72 | 换句话来讲:
73 | ==封装,也就是把客观事物抽象并封装成对象,即将数据成员、属性、方法和事件等集合在一个整体内。
74 | 通过访问控制,还可以隐藏内部成员,只允许可信的对象访问或操作自己的部分数据或方法== 75 | 76 | 77 | ### 继承 78 | 79 | __继承__是一种由已有的类创建新类的机制。 80 | 81 | 利用继承,我们可以先创建一个拥有共有属性的一般类,根据该一般类再创建具有特殊属性的新类,新类继承一般类的状态和行为,并根据需要增加它自己的新的状态和行为。
82 | 由继承而得到的类称为子类,被继承的类称为父类或超类。 83 | 84 | 即,
85 | 继承是允许使用现有类的功能,并在无需重新改写原来的类的情况下,对这些功能进行扩展。继承可以避免代码复制和相关的代码维护等问题
86 | 继承的过程,就是从一般到特殊的过程。被继承的类称为“基类(base class)”、“父类”或“超类(super class)”,通过继承创建的新类称为“子类(subclass)”或“派生类(derived class)” 87 | 88 | ==Java不支持多重继承,子类只能有一个父类(单一继承),但允许实现多个接口。== 89 | 90 | 在Java编程语言中,通过继承可利用已有的类,并扩展它的属性和方法。
91 | 这个已有的类可以是语言本身提供的、其他程序员编写的或程序员原来编写的。
92 | 继承在Java中无所不在。 93 | 94 | 95 | 96 | 97 | ### 多态(polymorphism) 98 | 99 | __多态__是指同样的消息被不同类型的对象接收时导致完全不同的行为。 100 | 多态性允许每个对象以自己的方式去响应共同的消息,从而允许用户以更明确的方式建立通用软件,提高软件开发的可维护性。
101 | 对象的多态是由封装和继承引出的面向对象程序设计语言的另一特征。
102 | 主要体现在两个方面: 103 | 104 | - 方法重载时实现的静态多态 105 | - 方法重载时实现的动态多态 106 | 107 | ==多态性使得我们的同一方法,可以有多种形式。== 108 | 109 | 另外父类中定义的属性或方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为,同一个属性或方法在父类及其各个子类中可以具有不同的语义。 110 | 111 | 例如,
112 | 假设设计了一个绘图软件,所有的图形(Square、Circle等)都继承于基类Shape,每种图形有自己特定的绘制方法(draw)的实现。 113 | 如果要显示画面的所有图形,则可以创建一个基类Shape的集合,其元素分别指向各子类对象,然后循环调用父类类型对象的绘制方法(draw),实际绘制根据当前赋值给它的子对象调用各自的绘制方法(draw),这就是多态性。
114 | 如果要扩展软件的功能,例如增加图形Eclipse,则只需要增加新的子类,并实现其绘制方法(draw)即可。 115 | 116 | 117 | ### 客观事物的抽象 118 | 119 | 为了使计算机能够处理和理解客观事物,==必须对事物进行抽象,以求得事物的本质。== 120 | 121 | 现实事物纷繁复杂,因此,在事物抽象过程中,必须忽略抽象事物中那些与当前目的无关的特征,求取对当前需求有直接影响的因素。
122 | 因此,针对客观事物的抽象必须掌握一定的抽象原则。 123 | 124 | 125 | 例如: 126 | 127 | 我们知道,当确定了一个圆形的__圆心位__置和圆的__半径__后,就可以在平面上确定一个圆。 128 | 129 | 因此,抽象出来的圆的要素为__圆心__和__半径__。 130 | 131 | 用数据结构来表示,如下: 132 | 133 | ~~~java 134 | class Circle{ 135 | point center; // 圆心 136 | float radius; // 半径 137 | } 138 | ~~~ 139 | 140 | 其中class是面向对象程序设计常用来定义“类”这种数据结构的关键字。 141 | 142 | 添加一些基本的行为如获取圆的面积,表示如下: 143 | 144 | ~~~java 145 | class Circle { 146 | point center; // 属性或成员 147 | float radius; // 属性或成员 148 | 149 | double getArea(){ // 方法 150 | return radius*radius*3.1415926; 151 | } 152 | } 153 | ~~~ 154 | 155 | 抽象原则包括__数据抽象__和__过程抽象__两个方面: 156 | 157 | - __数据抽象__ 就是定义对象的 __属性__ 158 | - __过程抽象__ 就是定义对象的 __操作__ 159 | 160 | 对象封装了数据和代码(数据和程序) 161 | 162 | --- 163 | 164 | ## 对象(object) 165 | 166 | 对象(object)是现实世界的实体或概念在计算机逻辑中的抽象表示。
167 | 在面向对象系统中,是系统中用来描述客观事物的一个实体,构成系统的一个基本单位。 168 | 169 | 一个对象由一组属性和对这组属性进行操作的一组服务构成。 170 | 171 | __属性__和__服务__是构成对象的两个主要因素,属性是一组数据结构的集合,表示对象的一种状态,对象的状态只供对象自身使用,用来描述静态特性,而服务是用来描述对象动态特征(行为)的一个操作序列,是对象一组功能的体现。 172 | 173 | ==对象的最主要特点是以数据为中心,它是一个集成了数据和其上操作的封装。==
174 | 封装隐藏了类的内部实现细节,强制类的使用者通过规定的接口访问对象,提高了代码的可维护性。
175 | 176 | 对象是具有唯一对象名和固定对外接口的一组属性和操作的集合,用来模拟组成或影响现实世界问题的一个或一组因素。 177 | 178 | 对象的主要特性: 179 | 180 | - 1.对象标识 181 | - 2.属性 182 | - 3.方法 183 | - 4.模块独立性 184 | - 5.动态连接性 185 | - 6.易维护性 186 | 187 | 对象是类的一个实例(对象不是找个女朋友),有状态和行为。 188 | 例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。 189 | 190 | ## 类(class) 191 | 192 | 在面向对象的编程语言中,类(class)是一个独立的程序单位,是对具有相同属性和方法的一组对象的抽象。 193 | 194 | 通过类可以对属于该类的全部对象进行统一的描述。 195 | 因此,在定义对象之前应先定义类。 196 | 197 | **类是一个模板,它描述一类对象的行为和状态。** 198 | 199 | 下图之中男孩女孩为类,而具体的每个人为该类的对象。 200 | ![](fig/object-class.jpg) 201 | 202 | 描述一个类需要指明下述三个方面: 203 | 204 | - (1)类标识(即类名) 205 | - (2)属性说明 206 | - (3)类的方法 207 | 208 | 类的声明举例: 209 | 210 | ~~~java 211 | class Circle { 212 | point center; // 属性或成员 213 | float radius; // 属性或成员 214 | 215 | double getArea() { // 方法 216 | return radius*radius*3.1415926; 217 | } 218 | } 219 | 220 | public class Rectangle extends Shapes implement Display{ 221 | …… // 类体 222 | } 223 | //下面的Rectangle类继承了Shapes父类,实现了接口 Display,是一个公共类。 224 | ~~~ 225 | 226 | 227 | ### 类变量 228 | 一个类可以包含以下类型变量: 229 | 230 | - **局部变量**:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。 231 | - **成员变量**:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。 232 | - **类变量**:类变量也声明在类中,方法体之外,但必须声明为static类型。 233 | 234 | ### 构造方法 235 | 236 | 每个类都有构造方法。 237 | 如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认构造方法。 238 | 239 | 在创建一个对象的时候,至少要调用一个构造方法。 240 | 构造方法的名称必须与类同名,一个类可以有多个构造方法。 241 | 242 | ### 创建对象 243 | 244 | 对象是根据类创建的。 245 | 在Java中,使用关键字**new**来创建一个新的对象。 246 | 247 | 创建对象需要以下三步: 248 | 249 | - **声明**:声明一个对象,包括对象名称和对象类型。 250 | - **实例化**:使用关键字**new**来创建一个对象。 251 | - **初始化**:使用**new**创建对象时,会调用构造方法初始化对象。 252 | 253 | 254 | ## 消息(message) 255 | 256 | 消息(message)是面向对象系统中实现对象间的通信和请求任务的操作,是要求某个对象执行其中某个功能操作的规格说明。
257 | 发送消息的对象称为发送者,接受消息的对象称为接收者。
258 | ==对象间的联系,只能通过消息来进行。==
259 | 对象在接收到消息时才被激活。 260 | 261 | 消息具有三个性质: 262 | 263 | - (1)同一对象可接收不同形式的多个消息,产生不同的响应。 264 | - (2)相同形式的消息可以送给不同对象,所做出的响应可以是截然不同的。 265 | - (3)消息的发送可以不考虑具体的接收者,对象可以响应消息,也可以对消息不予理会,对消息的响应并不是必需的。 266 | 267 | 268 | ## 面向对象系统的特性 269 | 270 | - 1.抽象性(abstract) 271 | - 2.封装性(encapsulation) 272 | - 3.继承性(inheritance) 273 | - 4.多态性(polymorphism) 274 | 275 | --- 276 | 277 | 278 | # 源文件声明规则 279 | 当在一个源文件中定义多个类,并且还有import语句和package语句时,要特别注意这些规则。 280 | 281 | - 一个源文件中只能有一个public类 282 | - 一个源文件可以有多个非public类 283 | - 源文件的名称应该和public类的类名保持一致。 284 | 285 | 例如:源文件中**public**类的类名是**Employee**,那么源文件应该命名为**Employee.java**。 286 | 287 | - 如果一个类定义在某个包中,那么package语句应该在源文件的首行。 288 | 如果源文件包含import语句,那么应该放在package语句和类定义之间。 289 | 如果没有package语句,那么import语句应该在源文件中最前面。 290 | 291 | - import语句和package语句对源文件中定义的所有类都有效。 292 | 在同一源文件中,不能给不同的类不同的包声明。 293 | 294 | - 类有若干种访问级别,并且类也分不同的类型:抽象类和final类等。 295 | 296 | - 除了上面提到的几种类型,Java还有一些特殊的类,如:**内部类**、**匿名类**。 297 | 298 | --- 299 | 300 | 本文档 Github : 301 | https://github.com/bushehui/Java_tutorial 302 | 303 | 306 | 307 | 310 | 311 | -------------------------------------------------------------------------------- /ch6_2.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Java语言面向对象 3 | --- 4 | 5 | 6 | [TOC] 7 | 8 | # 类 9 | 10 | 类是一个数据结构,类定义: 11 | 12 | - __数据类型的数据__(字段) 13 | - __行为__(方法和其他函数成员)。 14 | 15 | 16 | 对象是基于类的具体实体,有时称为类的实例(instance)。 17 | 18 | 进行Java程序设计,实际上就是定义类的过程。 19 | 一个Java源程序文件往往是由许多个类组成的。 20 | 21 | 从用户的角度看,Java源程序中的类分为两种: 22 | 23 | - 1. 系统定义的类,即Java类库。
24 | 基类:所有Java的类都派生自__Object__。
25 | Java提供的标准类库分布在一系列的包中,如java.lang,java.awt,java.net等, 26 | Java的类可组织在包(__package__)中。
27 | - 2. 用户自己定义的类。
28 | 编程的过程就是继承基类或标准类而创建、定义特殊子类的过程。 29 | 30 | 31 | 32 | ## 类的定义 33 | 34 | Java中类包括__成员变量__和__成员方法__两部分。 35 | 36 | - 类的__成员变量__可以是基本数据类型的数据或数组,也可以是一个类的实例;
37 | 用于描述状态的数据成员 38 | - 类的__方法__用于处理该类的数据。
39 | 用于描述操作的函数成员 40 | 41 | ![](fig/classNumber.png) 42 | 43 | ### 类的定义格式: 44 | 45 | ~~~java 46 | [类的修饰字] class 类名称 [extends 父类名称][implements 接口名称列表] 47 | { 48 | 变量定义及初始化; 49 | 50 | 方法定义及方法体; 51 | } 52 | ~~~ 53 | 54 | **例如** 55 | 56 | ~~~java 57 | class Circle { 58 | point center; // 属性或成员 59 | float radius; // 属性或成员 60 | 61 | double getArea(){ // 方法 62 | return radius*radius*3.1415926; 63 | } 64 | } 65 | 66 | public class Rectangle extends Shapes implement Display{ 67 | …… // 类体 68 | } 69 | //下面的Rectangle类继承了Shapes父类,实现了接口Display,是一个公共类。 70 | ~~~ 71 | 72 | 73 | __类名称__: 74 | 75 | - 习惯上类名的第一个字母大写,但这不是必须的。 76 | - 类的名字不能是Java中的关键字,要符合标识符规定,即名字可以由字母,下划线,数字或美圆符号组成,并且第一个字符不能是数字。 77 | - 但给类命名时,最好遵守如下习惯:
78 | -- 如果类名使用拉丁字母,那么名字的首写字母使用大写字母,例如Hello、Time、People等。
79 | -- 类名最好见名知意,当类名由几个”单词”复合而成时,每个单词的首写字母使用大写,如BeijingTime,CarNumber等。 80 | 81 | 82 | ### 关于类定义的说明 83 | 84 | #### 类的修饰字: 85 | 86 | >[public | default(可缺省,非公开类)] [abstract | final] 87 | 88 | |类的修饰字| | 89 | |:---|:---| 90 | |public|允许其他类(没有限制)访问本类,一个源文件仅可以有一个public类,且与文件同名。| 91 | |default(缺省)|可被当前包中的其他类访问;| 92 | |abstract|没有实例的抽象概念类,类不能被实例化,包含有未实现的方法。 | 93 | |final|不能再被扩展,不包含子类的类;易于安全性的实现,或用于创建固定功能的类| 94 | 95 | 注意: 96 | 97 | __abstract__和__final__不能同时作为一个类的修饰符。 98 | 99 | 每个类都拥有自己的名字空间,即指类及其方法和变量可以在一定的范围内知道彼此的存在,可以使用。 100 | 101 | 102 | #### 父类继承声明: 103 | 104 | >extends 父类名 105 | 106 | - 用来表明新创建的类继承哪个类,被继承的类称为此类的父类。 107 | - extends后面只能跟一个父类名。 108 | 109 | #### 实现接口(interface): 110 | 111 | >implements 接口名 112 | 113 | 用来表明这个类实现了哪些接口,接口名可以有多个。 114 | 115 | 例如下面的类是合法的: 116 | 117 | ~~~java 118 | class MyC1ass { 119 | //空类,没有任何用处,但是合法 120 | } 121 | ~~~ 122 | 123 | 又如:下面的Rectangle类继承了Shapes父类,实现了接口Display,是一个公共类。 124 | 125 | ~~~java 126 | public class Rectangle extends Shapes implement Display{ 127 | …… //类体 128 | } 129 | ~~~ 130 | 131 | 132 | #### 类体 133 | 134 | 类体中定义了该类所有的成员变量和该类所支持的方法,其格式说明如下: 135 | 136 | ~~~java 137 | { 138 | [成员变量说明] 139 | [成员方法说明] 140 | } 141 | ~~~ 142 | 143 | ~~~java 144 | { 145 | [public | protected | private ] [static] 146 | [final] [transient] [volatile] 147 | type variableName; //成员变量 148 | 149 | [public | protected | private ] [static] 150 | [final | abstract] [native] [synchronized] 151 | returnType methodName([paramList]) [throws exceptionList] 152 | {statements} //成员方法 153 | } 154 | ~~~ 155 | 156 | #### 类定义中成员变量的声明 157 | 158 | 成员变量又称值域。
159 | 成员变量的说明类似于方法的局部变量说明,所不同的是,成员变量定义在类中,是类成员的一部分,整个类都可以访问它。 160 | 161 | Java中成员变量说明形式如下 162 | 163 | >[变量修饰字] 变量数据类型 变量名1,变量名2[=变量初值]…; 164 | 165 | 例如: 166 | 167 | ~~~java 168 | private int number; 169 | ~~~ 170 | 171 | 类的成员变量在定义它的类内部,可以直接通过成员变量名来访问。 172 | 173 | ~~~java 174 | class Circle { 175 | static final float PI=3.1415926f; // 常量 176 | 177 | private Point center; // 属性或成员 178 | private float radius; // 属性或成员 179 | 180 | static Color color; 181 | 182 | public float area; 183 | 184 | float getArea(){ // 方法 185 | return radius*radius*PI; //内部访问成员变量 186 | } 187 | } 188 | ~~~ 189 | 190 | 如果从类的外部访问,类变量和类对象变量的使用方法是不同。
191 | 访问类变量的格式如下: 192 | 193 | >类名.类变量名 194 | 195 | 例如我们可以采用下面形式访问上例中的静态变量color的: 196 | 197 | >Circle.color, 198 | 199 | 由此可见,访问类变量与类的对象构造和对象都无关。
200 | 类变量名必须用static修饰。 201 | 访问实例变量的格式如下: 202 | 203 | >对象名.实例变量名 204 | 205 | 例如 206 | 207 | ~~~java 208 | Circle c1=new Circle(); //c1是对象名 209 | System.out.println(“area=”+c1.area); 210 | System.out.println(“Color=”+Circle.color); 211 | ~~~ 212 | 213 | 214 | 215 | #### 类定义中方法的声明 216 | 217 | 在Java中,方法总是Java类的一个组成部分。
218 | 通过类的方法,改变对象的状态。
219 | 方法说明分为方法首部说明和方法体两部分。
220 | 方法首部说明的格式如下: 221 | 222 | ~~~java 223 | [方法修饰字] 返回类型 方法名称(参数1,参数2,…) [throws exceptionList] 224 | { 225 | …(statements;) //方法体:方法的内容 226 | } 227 | ~~~ 228 | 229 | 可能的选项有: 230 | 231 | ~~~ 232 | [public | protected | private ] 233 | [static][final | abstract] [native] [synchronized] 234 | returnType methodName([paramList])[throws exceptionList]//方法声明 {……} 235 | ~~~ 236 | 237 | 238 | ##### 方法体 239 | 240 | - 方法体是实现这个方法的代码段,它由“{”和“}”括起来的语句序列构成。 241 | - 方法体也可以是一个分号“;”,表示无方法体,该方法没有实现。 242 | - 当且仅当方法的修饰符中有abstract或native时,方法才无方法体。 243 | 244 | 例如:求解三角形问题时可以编写Triangle类。 245 | 246 | ~~~java 247 | class Triangle{ 248 | double sideA,sideB,sideC; //三角形的三边 249 | 250 | void setSide(double a,double b,double c){ //该方法用来赋初值 251 | sideA=a; 252 | sideB=b; 253 | sideC=c; 254 | } 255 | 256 | boolean isOrNotTriangle(){ //判断是否是三角形的方法 257 | if(sideA+sideB>sideC&&sideA+sideC>sideB&&sideB+sideC>sideA){ 258 | return true; 259 | } 260 | else { 261 | return flase; 262 | } 263 | } 264 | } 265 | ~~~ 266 | 267 | ##### 方法的调用 268 | 269 | 成员方法又分为__类方法__(静态方法)和__对象方法__(实例方法)两类。 270 | 271 | 他们的调用是有区别的。 272 | 273 | 276 | 类方法调用形式如下: 277 | 278 | >类名.类静态方法名(实参列表) 279 | 280 | 对象方法调用形式如下: 281 | 282 | >类对象名.类非静态方法名(实参列表) 283 | 284 | 例如 285 | 286 | ~~~java 287 | Circle c1=new Circle(); // r1是对象名 288 | System.out.println(“area=”+c1.getArea()); 289 | ~~~ 290 | 291 | 292 | #### 修饰符 293 | 294 | |访问控制符|访问权限| 295 | |:---|:---| 296 | |public|可被所有其他类引用| 297 | |protected|该类自身、子类、同一包中的其他类| 298 | |private|仅可被该类自身引用和修改,不能被其他任何类(包括子类)引用| 299 | |default(缺省)|本包中的类| 300 | |static| 类变量或类字段,对所有的实例一致,引用时前缀可使用类名或对象名,属于类| 301 | |final|数值不变常量,定义同时应对其进行初始化| 302 | |volatile|异步控制修饰符,表示多个并发线程共享的变量,这使得各线程对该变量的访问保持一致| 303 | |transient|与对象序列化有关| 304 | 305 | 306 | ##### static:静态方法,又称类方法
307 | 使用类名或对象名作为前缀,建议使用类名
308 | 在方法体中只能使用static变量和static方法或访问自己的局部变量
309 | 当类成员声明中含有static修饰符时,它声明为静态成员;否则为实例成员(非静态成员) 310 | 311 | 312 | **static的作用:** 313 | 314 | - 类初始化 315 | 316 | - 静态成员变量(共享数据) 317 | 318 | ~~~ 319 | public class MathUtil{ 320 | //定义了一个类静态常量PI 321 | public static final double PI=3.1415926; 322 | } 323 | ~~~ 324 | 325 | 这个PI被static修饰后,要想使用,必须通过“类名.类成员变量名"这种方法使用。
326 | 其它例子如前面程序经常使用的System.out.println(),out是System类的一个类成员,其类型是PrintStream ,所以就通过类名System就直接引用了。
327 | 再比如,Integer.MAX_VALUE则表示的是一个整型类能够表示的最大数。 328 | 329 | - 静态方法(共享操作) 330 | 331 | 在没有任何对象的前提下,仅通过类本身来调用静态方法;
332 | 没有this参数的方法;
333 | 类的静态方法可以访问其他类的静态方法和静态域,虽然Java没有全局方法;
334 | 335 | 一个特例:main方法; 336 | 337 | ~~~java 338 | public class Circle { 339 | public static final double PI=3.1415926;//类成员变量 340 | 341 | //构造方法,之所以定义为私有,是因为不希望用new运算符创建实例。 342 | private Circle() { 343 | super(); 344 | } 345 | 346 | public static double getArea(double r){ 347 | return PI*r*r; 348 | } 349 | 350 | public static void main(String[] args) { 351 | System.out.println("半径为10的圆面积是"+Circle.getArea(10)); 352 | System.out.println("半径为8的圆面积是"+Circle.getArea(8)); 353 | } 354 | } 355 | ~~~ 356 | 357 | 358 | 359 | 360 | ##### abstract: 361 | 只有接口没有语句,要在子类中通过重新定义(override)来实现
362 | 363 | ##### final: 364 | 不能被重新定义(override)
365 | 366 | 常量字段必须在声明时赋值或在类的构造方法内或初始化代码块中被赋值一次
367 | 常量字段的值不能更改
368 | 给常量字段赋初值时,一个常量字段可以依赖于同一程序内之前声明的其他常量,但不能依赖于同一程序内之后声明的其他常量
369 | 静态常量字段属于静态成员,一般通过类名来引用:类名.静态字段名
370 | 实例常量字段必须通过对象实例来引用:对象.实例字段名
371 | 372 | 373 | 例:定义圆类 Circle.java 374 | 375 | ~~~java 376 | // Circle.java 377 | 378 | public class Circle { 379 | private double radius = 1; // 圆的半径 380 | private static int numberOfObjects = 0; // 创建的圆的个数 381 | 382 | // 以半径1创建一个圆,圆的个数加1 383 | public Circle() { 384 | numberOfObjects++; 385 | } 386 | 387 | // 以半径newRadius创建一个圆,圆的个数加1 388 | public Circle(double newRadius) { 389 | radius = newRadius; 390 | numberOfObjects++; 391 | } 392 | 393 | // 获取圆的半径 394 | public double getRadius() { 395 | return radius; 396 | } 397 | 398 | // 设置圆的半径 399 | public void setRadius(double newRadius) { 400 | radius = (newRadius >= 0) ? newRadius : 0; 401 | } 402 | 403 | // 获取圆的个数 404 | public static int getNumberOfObjects() { 405 | return numberOfObjects; 406 | } 407 | 408 | // 返回圆的面积 409 | public double findArea() { 410 | return radius * radius * 3.14159; 411 | } 412 | } 413 | ~~~ 414 | 415 | **解析** 416 | 417 | - 该类中定义了私有成员变量radius,而方法setRadius中的局部变量radius与其同名,在setRadius方法体内成员变量radius被隐藏,所以使用this关键字访问成员变量。 418 | - setRadius方法的功能是:若形参radius的值大于等于$0$,则把形参radius的值赋给成员变量radius,否则给成员变量radius赋值为$0$。 419 | - 该类的定义中没有使用setArea()方法设置圆的面积,而是在创建一个圆时就设置了圆的面积,符合自然规律。 420 | - 当使用setRadius方法重新设置圆的半径时,相应地修改圆的面积。 421 | 422 | ### 封装 423 | 424 | 在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部份包装、隐藏起来的方法。 425 | 426 | **封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。** 427 | 428 | - 要访问该类的代码和数据,必须通过严格的接口控制。 429 | 430 | - 封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。 431 | 432 | - 适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。 433 | 434 | 435 | **封装的优点** : 436 | 437 | 1. 良好的封装能够减少耦合。 438 | 2. 类内部的结构可以自由修改。 439 | 3. 可以对成员变量进行更精确的控制。 440 | 4. 隐藏信息,实现细节。 441 | 442 | 443 | 444 | 445 | ### 构造方法 446 | 447 | 方法名和所在类的类名完全相同的方法称为构造方法。 448 | ==执行类的实例的初始化工作。== 449 | 450 | 每个类都有构造方法,如果没有显式声明构造方法,则编译器会自动生成一个默认的无参数的构造方法。 451 | 默认构造方法实例化对象,并将未赋初值的字段设置为默认值。 452 | 453 | Java类初始化时,首先初始化静态字段,故在给实例字段赋初值时,可以引用类中定义的静态字段(包括从父类继承的静态字段)。 454 | 但给静态字段赋初值时,不能引用类中定义的实例字段 455 | 字段的初始化按位置顺序执行,故后续位置的字段的初始化,可以使用之前初始化的字段。 456 | 457 | 458 | 如果构造方法被声明为private类型,则这个构造方法不能从类外访问。
459 | 如果一个类的所有构造方法都被声明为private类型,则不能在创建该类的对象实例。
460 | 私有构造方法一般用于只包含静态成员的类。通过添加一个空的私有实例构造方法,可以阻止其实例化,以确保程序只能通过类名来引用所有的静态成员。 461 | 462 | 463 | 构造方法具有下列特性: 464 | 465 | - (1)构造方法名必须和类名完全相同。 466 | - (2)构造方法不具有任何返回值类型,如果写上任何一种返回值类型(包括关键字void)则该方法不再是构造方法,而成为普通的成员方法。 467 | - (3)构造方法也可以重载。重载构造方法的目的是使类对象具有不同的初始值,为类对象的初始化提供方便。 468 | - (4)当使用new运算符创建对象时,系统会自动调用构造方法,构造方法起着初始化对象的作用。 469 | - (5)当在一个类中没有显式定义构造方法时,系统会提供一个默认构造方法。默认构造方法没有任何形式参数,并且方法体为空。 470 | - (6)不能使用static、final、abstract、native和synchronized修饰符修饰构造方法。 471 | 472 | 注意:
473 | 只要用户定义了构造方法(不一定是无参构造方法),Java语言就不再提供默认的构造方法。
474 | 如果为类定义了一个带参数的构造方法,还想使用无参构造方法,则用户必须自己定义。
475 | 建议用户自定义类的无参构造方法。 476 | 477 | 478 | 类是创建对象的模板。 479 | 当使用一个类创建了一个对象时,我们也说我们给出了这个类的一个实例。 480 | 通常的格式为: 481 | 482 | >Type objectName=new Type([parameterList]); 483 | 484 | 创建一个对象包括对象的声明、为对象分配内存空间和赋初值三个步骤。 485 | 486 | 1、对象的声明格式为: 487 | 488 | >类的名字 对象名字; 489 | 490 | 如 491 | 492 | >People zhangPing; 493 | 494 | 或 495 | 496 | >People zhangPing,LiYong; 497 | 498 | 这里People是一个类的名字,zhangPing是我们声明的对象的名字. 499 | 500 | 2、 为声明的对象分配内存. 501 | 502 | 使用new运算符和类的构造方法为声明的对象分配内存,如果类中没有构造方法,系统会调用默认的构造方法。 503 | 504 | 默认的构造方法是无参数的,构造方法的名字必须和类名相同。 505 | 用new可以为一个类实例化多个不同的对象,这些对象分别占用不同的内存空间,因此改变其中一个对象的状态不会影响其他对象的状态。 506 | 507 | 3、最后一步是执行构造方法,进行初始化。 508 | 509 | >zhangPing=new People(“20040101”); 510 | >liYong=new People(“20040102”); //实例化另外一个对象。 511 | 512 | 上面三个步骤,通常可以写成如下简洁的形式: 513 | 514 | >People zhangPing=new People(“20040101”); 515 | 516 | 例
517 | 建立雇员信息类EmpInfo,并实例化对象,然后打印出若干信息。 518 | 519 | ~~~java 520 | // EmpInfo.java 521 | public class EmpInfo { 522 | String name; // 雇员的姓名 523 | String designation; // 雇员的职务 524 | String department; // 雇员的部门 525 | 526 | void print() { // 成员方法 527 | System.out.println(name + " is " + designation + " at " + department); 528 | } 529 | 530 | public static void main(String argv[]){ 531 | mpInfo employee = new EmpInfo(); // 创建对象并实例化 532 | employee.name = " Robert Javaman " ; // 给成员变量赋值 533 | employee.designation = " Manager " ; //给成员变量赋值 534 | employee.department = "Coffee Shop"; //给成员变量赋值 535 | employee.print(); // 调用方法print() 536 | } 537 | } 538 | ~~~ 539 | 540 | 运行结果如下: 541 | 542 | >Robert Javaman is Manager at Coffee Shop 543 | 544 | 每当由类构造对象时都要调用该类特定的构造方法,在Java中,==每个类都至少有一个构造方法==。
545 | 构造方法可以确保用户正确地构造类的对象,同时,构造方法也会对对象作初始化工作。
546 | 547 | 构造方法说明形式如下: 548 | 549 | >[构造方法修饰符] 方法名([形式参数列表]) 550 | > [throws异常列表] {方法体 } 551 | 552 | 构造方法不能像一般的方法那样被直接调用,它是在构造类的实例的时候被new关键字调用的。 553 | 当我们构造一个类的实例的时候,编译器主要完成以下三件事情: 554 | 555 | - (1) 为对象分配内存空间; 556 | - (2) 初始化对象中的实例变量的值,初始值可以是缺省值,或者变量按指定的值初始化; 557 | - (3) 调用对象的构造方法。 558 | 559 | 一个类的构造方法可以有多个,它们都具有相同的方法名,即类名。 560 | ==编译器根据参数的类型来决定调用哪个构造方法。== 561 | 这就是构造方法的多态。 562 | 563 | 构造方法分为缺省的构造方法(不带参数)和带参数的构造方法。 564 | 565 | (1)缺省的构造方法
566 | 如果类的定义没有编写构造方法,Java语言会自动为用户提供。这个由Java自动提供的构造方法就是所谓的缺省构造方法。缺省的构造方法确保每个Java类都至少有一个构造方法,该方法应符合方法的定义。 567 | 568 | 构造方法分为缺省的构造方法(不带参数)和带参数的构造方法。 569 | 570 | (2)带参数的构造方法
571 | 带有参数的构造方法能够实现这样的功能:当构造一个新对象时,类构造方法可以按需要将一些指定的参数传递给对象的变量。 572 | 573 | 574 | 575 | ### 方法重载 576 | 577 | 578 | 方法重载(Method Overloading)就是一个类中可以有多个方法具有相同的名字,但这些方法的参数必须不同,即或者是参数的个数不同,或者是参数的类型不同,或者是返回值不同。 这也是面向对象的程序设计中的奇妙之处,重载反映了大千世界的变化。
579 | 580 | 如果几个方法的方法名相同,只是方法形参个数或形参类型有所不同,则称这几个方法为__重载方法__。  581 | 582 | 从另外的含义上来讲,重载也可以看成是同一个方法具有不同的版本,每个版本之间在参数特征和返回值方面有差别。 583 | ==重载是Java实现多态性的一种方式。== 584 | 585 | 当调用一个重载方法时,JVM自动根据当前对方法的调用形式在类的定义中匹配形式符合的成员方法,匹配成功后,执行参数类型、数量均相同的成员方法。方法重载在Java的API类库中得到大量的使用。 586 | 587 | 注意:
588 | ==如果几个方法的方法名、方法的形参个数和形参类型均相同,只是方法的返回值类型不同,则不称其为重载方法,编译时会出错。== 589 | 590 | 例如有如下的两个重载方法说明:  591 | 592 | ~~~java 593 | int max(int num1, double num2); 594 | double max(double num1, int num2);  595 | ~~~ 596 | 当使用max(1, 4)方法调用时,编译器不能确定调用哪一个方法更合适,这称为方法调用的二义性,二义性的方法调用会引起编译时的错误。 597 | 598 | 599 | ~~~java 600 | class Demo2{ 601 | int a,b; 602 | 603 | int method(){ //成员方法一 604 | return a+b; 605 | } 606 | 607 | int method(int c){ //成员方法二 608 | return a+b+c; 609 | } 610 | 611 | int method(int c,int d){ //成员方法三 612 | return a+b+c+d; 613 | } 614 | 615 | Demo2(int a,int b) { //构造方法 616 | this.a = a; 617 | this.b = b; 618 | } 619 | } 620 | ~~~ 621 | 622 | 关于成员方法重载的例子 623 | 624 | ~~~java 625 | public class DemoOverload{ 626 | public static void main(String args[]){ 627 | Demo2 aDemo2 = new Demo2(1,2); //实例化 628 | 629 | int a = aDemo2.method(); //调用成员方法一 630 | System.out.println(a); 631 | 632 | int b = aDemo2.method(3); //调用成员方法二 633 | System.out.println(b); 634 | 635 | int c = aDemo2.method(3,4); //调用成员方法三 636 | System.out.println(c); 637 | } 638 | } 639 | ~~~ 640 | 641 | 上面程序的运行结果为: 642 | 643 | >3 644 | >6 645 | >10 646 | 647 | 648 | 构造方法也可以重载, 649 | 650 | ~~~java 651 | // ConstructionOverload.java 652 | class Demo{ 653 | int a,b,c;//成员变量 654 | 655 | public Demo(){} //构造方法1 656 | 657 | public Demo(int a) { //构造方法2 658 | this.a = a; 659 | } 660 | 661 | public Demo(int a,int b) { //构造方法3 662 | this.a = a; 663 | this.b = b; 664 | } 665 | 666 | public Demo(int a,int b,int c) { //构造方法4 667 | this.a = a; 668 | this.b = b; 669 | this.c = c; 670 | } 671 | } 672 | ~~~ 673 | 674 | 方法Demo()被定义了四次,每次参数不同。
675 | 第一个构造方法,没有参数,也没有方法体,它和系统的缺省构造方法是一致的。 676 | 缺省的构造方法确保每个Java类都至少有一个构造方法。 677 | 如果程序中给出了带参数的构造方法,而没有给出缺省构造方法,这时调用缺省构造方法将导致错误。
678 | 在调用构造方法时,由于使用的是同一方法名,因此根据构造方法的参数就能找到需要运行的哪个方法。 679 | 680 | ~~~ 681 | public class ConstructionOverload{ 682 | public static void main(String args[]){ 683 | 684 | //应用第一种构造方法 685 | Demo aDemo = new Demo(); 686 | System.out.println("方法一成员变量a:"+aDemo.a); 687 | System.out.println("方法一成员变量b:"+aDemo.b); 688 | System.out.println("方法一成员变量c:"+aDemo.c); 689 | 690 | //应用第二种构造方法 691 | Demo bDemo = new Demo(1); 692 | System.out.println("方法二成员变量a:"+bDemo.a); 693 | System.out.println("方法二成员变量b:"+bDemo.b); 694 | System.out.println("方法二成员变量c:"+bDemo.c); 695 | 696 | …… 697 | ~~~ 698 | 699 | 700 | ##练习: 701 | 702 | 一个类Foo的定义如下: 703 | 704 | ~~~java 705 | public class Foo{ 706 | int i; 707 | static String s; 708 | void imethod(){ } 709 | static void smethod(){ } 710 | } 711 | ~~~ 712 | 713 | 设f是Foo的一个实例,则下述语句正确吗? 714 | 715 | - [ ]System.out.println(f.i); 716 | - [ ]System.out.println(f.s); 717 | - [ ]f.imethod(); 718 | - [ ]f.smethod(); 719 | - [ ]System.out.println(Foo.i); 720 | - [ ]System.out.println(Foo.s); 721 | - [ ]Foo.imethod(); 722 | - [ ]Foo.smethod(); 723 | 724 | --- 725 | 726 | 创建1个名为Book的类,用来代表1本书。类中有3个属性,分别为String类型的书名,int类型的pageCount和double类型的price。 727 | - 创建1个Book类对象,然后分别给类中的三个属性赋值,最后将该Book类对象的3个属性值输出到控制台。 728 | - 创建book1和book2这两个Book类的引用,让他们都指向上述Book类对象,并通过这两个引用修改上述Book类对象的属性值并输出到控制台。 729 | 730 | 731 | 732 | --- 733 | 734 | 本文档 Github : 735 | https://github.com/bushehui/Java_tutorial 736 | 737 | 740 | 741 | 744 | 745 | -------------------------------------------------------------------------------- /ch6_3.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Java语言面向对象 3 | --- 4 | 5 | [TOC] 6 | 7 | 8 | # 对象的定义和使用 9 | 10 | 在程序中创建对象的目的是使用对象。
11 | ==创建一个对象就要为对象的各个成员变量分配存储空间。== 12 | 13 | 14 | ## 创建对象 15 | 16 | - 创建一个类,就创建了一种新的数据类型。 17 | - 创建对象也称为类的实例化。 18 | 19 | 创建对象包括两个步骤:__声明对象引用变量__(即对象名)和__实例化对象__(即为对象分配存储空间)或者将两个步骤合二为一。 20 | 21 | ### 声明对象 22 | 23 | > 类名 对象名表; 24 | 25 | 其中: 26 | 27 | - 类名是指对象所属类的名字,它是在声明类时定义的; 28 | - 对象名表是指一个或多个对象名,若为多个对象名时,对象名之间用半角逗号进行分隔。 29 | 30 | 注意: 31 | ==声明对象实质上是声明了对象引用变量,而并没有为对象开辟内存空间,对象引用变量存放对象的内存单元起始地址。== 32 | 33 | ### 为对象分配内存空间 34 | 35 | 使用new运算符和类的构造方法为声明的对象分配内存空间,如果类中没有显式定义构造方法,系统会调用默认的无参构造方法。 36 | 37 | 为对象分配内存空间的格式有如下两种方式: 38 | 39 | - 方式1 40 | 41 | >对象名 = new 构造方法([实参列表]); 42 | 43 | ~~~java 44 | circleOne = new Circle(); 45 | // 此时circleOne引用被分配内存空间的真实地址 46 | circleTwo = new Circle(2.0); 47 | ~~~ 48 | 49 | -方式2 50 | 51 | >类名 对象名 = new 构造方法([实参列表]); 52 | 53 | 54 | ~~~java 55 | Circle circleTwo = new Circle(2.0); 56 | ~~~ 57 | 58 | 或者 59 | 60 | ~~~java 61 | // EmpInfo.java 62 | public class EmpInfo { 63 | String name; // 雇员的姓名 64 | String designation; // 雇员的职务 65 | String department; // 雇员的部门 66 | 67 | // 带参数的构造方法 68 | public EmpInfoC(String name,String desi,String depa) { 69 | this.name=name; 70 | this.designation=desi; 71 | this.department=depa; 72 | } 73 | 74 | void print() { // 成员方法 75 | System.out.println(name + " is " + designation + " at " + department); 76 | } 77 | 78 | public static void main(String argv[]){ 79 | EmpInfoC employee = 80 | new EmpInfoC("Robert Javaman ","Manager","Coffee Shop"); 81 | employee.print(); // 调用方法print() 82 | } 83 | } 84 | ~~~ 85 | 86 | 运行结果如下: 87 | 88 | >Robert Javaman is Manager at Coffee Shop 89 | 90 | 91 | 92 | #### 对象的使用 93 | 94 | ==创建一个对象就要为对象的各个成员变量分配存储空间。== 95 | 96 | 可以通过引用对象的成员来使用对象,对象成员变量的引用方式如下:  97 | 98 | >对象名.成员变量名 99 | 100 | 对象成员方法的引用方式如下:  101 | 102 | >对象名.成员方法名(实参列表) 103 | 104 | 105 | #### 对象的清除 106 | 107 | - Java运行时系统通过垃圾自动回收机制周期性地释放无用对象所使用的内存,完成垃圾的自动回收。 108 | 109 | - 当一个对象的引用为空时,该对象称为一个无用对象。 110 | 111 | - Java的垃圾收集器自动扫描对象的动态内存区,对被引用的对象加标记,然后把没有引用的对象作为垃圾收集起来并释放。 112 | 113 | 垃圾收集器作为一个线程运行,当系统的内存用尽或程序中调用System.gc()要求进行垃圾收集时,垃圾收集线程与系统同步运行,否则垃圾收集器在系统空闲时异步地执行。
114 | 在对象作为垃圾被收集器释放前,Java运行时系统会自动调用对象的方法finialize(),使它清除自己所使用的资源。 115 | 116 | - 垃圾收集器以较低优先级在系统空闲周期中执行,一次垃圾的收集速度比较慢,在某些情况下,我们也可以通过调用System类的gc()方法,即调用System.gc()显示执行垃圾收集。 117 | 118 | - 析构方法finalize()
119 | 垃圾收集器自动调用对象的finalize(),释放当前对象所使用的资源。
120 | gc()方法调用finalize()。
121 | 在类的定义中,除了必须定义创建类实例的方法外,还可以在定义中提供用于对象清除的方法finialize(),它的格式如下: 122 | 123 | >protected void finalize() throws Throwable{ //撤销对象 } 124 | 125 | finalize()方法是类java.long.Object中最基本的方法。
126 | 然而,在某些情况下,当一个类被破坏后,需要亲自执行一些垃圾收集器不能处理的特殊清理工作。 127 | 128 | 129 | #### 方法的参数传递 130 | 131 | 进行方法调用时,需要提供实参,他们必须与方法定义中所对应的形参次序相同,这叫做__参数顺序匹配__。
132 | ==实参必须与方法头中的形参在次序上和数量上匹配,在类型上兼容。==
133 | 类型兼容是指不需要经过显式的类型转换,实参的值就可以传递给形参。
134 | 例如将int型的实参值传递给double型形参。 135 | 136 | 方法调用的格式有以下3种形式: 137 | 138 | - 形式一:成员方法名(实参列表) 139 | - 形式二:表达式.成员方法名(实参列表) 140 | - 形式三:类名.静态成员方法名(实参列表) 141 | 142 | 在Java的方法调用中,==方法中的参数是以传值的形式进行的,不管它是什么数据类型。==
143 | 如果是基本数据类型,则将实参的值传递给形参,改变方法内部的形参的值不会影响方法外部的实参值。
144 | 无论形参在方法中如何改变,实参均不受影响。
145 | 如果是类类型,则传入的是引用的一个拷贝。
146 | 147 | 如同可以给方法传递基本数据类型一样,也可以向方法传递类类型的对象,称其为引用传递。
148 | 引用传递传入的是引用的一个拷贝,归根结底还是传的值。
149 | 150 | ##### Example 1 151 | 152 | ~~~java 153 | public static void tripleValue(double x) { 154 | x = x*3; 155 | } 156 | ~~~ 157 | 158 | ~~~java 159 | double percent = 20; 160 | tripleValue(percent); 161 | ~~~ 162 | 163 | - x被初始化为percent的一个拷贝,x=20; 164 | - x = x * 3, x=60; 165 | - 结束tripleValue方法后,x不再使用; 166 | 167 | ##### Example 2 168 | 169 | ~~~java 170 | class Employee { 171 | private int salary = 0; 172 | public void raiseSalary(int number) { 173 | salary = salary + number; 174 | } 175 | } 176 | ~~~ 177 | 178 | ~~~java 179 | public static void tripleValue(Employee x) { 180 | x.raiseSalary(200); 181 | } 182 | ~~~ 183 | 184 | ~~~java 185 | Employee harry = new Employee(); 186 | tripleValue(harry); 187 | ~~~ 188 | 189 | - x被初始化为harry的一个拷贝,这里是一个对象的引用; 190 | - x和harry同时引用的那个Employee对象.salary提高了200元; 191 | - 结束tripleValue方法后,x不再使用,但是harry继续引用那个salary提高了200元的Employee对象; 192 | 193 | 194 | 195 | 196 | ### 变量与方法 197 | 198 | 在类的数据成员和方法成员前用__static__关键字修饰的分别称为类变量和类方法,也称为静态变量和静态方法,非静态的又分别称为实例变量和实例方法。
199 | 在生成每个类的实例对象时,Java运行时系统为每个对象分配一块内存,然后可以通过对象引用变量来访问这些对象的实例变量。
200 | 不同对象的实例变量是不同的。 201 | 202 | 类变量可用来在实例对象之间进行通信或跟踪该类实例的数目。
203 | 对于不是private类型的类变量,建议通过类名直接访问类变量,而不像实例变量那样需要通过实例对象才能访问。 204 | 205 | **注意**: 206 | 207 | - (1)Java中没有全局变量,但类变量是在一个类的所有实例对象中都可以访问的变量,在一定程度上类似于其他语言中的全局变量。 208 | - (2)实例方法可以对当前对象的实例变量进行操作,也可以对类变量进行操作,但类方法不能访问实例变量。 209 | 210 | 211 | #### 实例方法的调用形式如下: 212 | 213 | >对象名.实例方法名(实参列表); 214 | 215 | 类方法由类名直接调用,其调用形式如下: 216 | 217 | >类名.类方法名(实参列表); 218 | 219 | 220 | 关于类方法的使用,有如下一些限制: 221 | 222 | - 在类方法中没有__this__关键字,不能访问所属类的实例变量和实例方法,只能访问方法体内定义的局部变量、该方法的形式参数和类变量; 223 | - 在类方法中不能使用__super__和__this__关键字; 224 | - main()方法是一个静态方法。因为它是程序的入口点,这可以使JVM不创建实例对象就可以运行该方法。 225 | 226 | #### 变量的作用域 227 | ==实例变量和类变量的作用域是整个类,它们可以在类中任何位置说明。==
228 | 在方法中说明的变量称为局部变量,局部变量的作用域从声明它的位置开始到包含它的块尾。
229 | 类的实例变量和类变量只能声明一次,但是局部变量可以在互不嵌套的块内多次声明,在同一嵌套块中只能声明一次。 230 | 231 | 232 | #### 变量的初始值 233 | 234 | 如果没有对类的成员变量赋初值,则Java会对其赋默认值,对不同类型的成员变量赋以不同的默认值,如下所示: 235 | 236 | ||| 237 | |:---|:---| 238 | |引用类型|null| 239 | |数值类型|0| 240 | |boolean|false| 241 | |char|'\u0000'|  242 | 243 | 注意:
244 | 对于方法体内的局部变量,Java不提供初始值。
245 | 程序员必须对其赋初值,否则会出现编译错误。 246 | 247 | 248 | #### this关键字 249 | 250 | 关键字__this__用来指向当前对象或类的实例变量。
251 | 如果局部变量与实例变量重名,则局部变量优先,同名的实例变量或类变量被隐藏。 252 | 253 | 用“类名.类变量名”可以访问隐藏的类变量,用this关键字可以访问隐藏的实例变量。 254 | 255 | 例: 256 | 257 | ~~~java 258 | class TestThis{ 259 | int day = 1; // 实例变量day 260 | 261 | void setDay(int day){ 262 | this.day = day; 263 | } 264 | } 265 | ~~~ 266 | 267 | 当一个构造方法需要调用本类的另一个构造方法时,可以使用this关键字,同时这个调用语句应该是整个构造方法的第一个可执行语句。 268 | 269 | 例: 270 | 271 | ~~~java 272 | public class Circle { 273 | private double radius; 274 |   275 |   public Circle(double radius) { 276 | this.radius = radius; 277 | } 278 | 279 | public Circle() { 280 | this(1.0); 281 | } 282 | 283 | public double findArea() { 284 | return Math.PI * radius * radius; } 285 | } 286 | ~~~ 287 | 288 | 每个对象的每个实例方法都拥有一个this变量指向对象自己,供自己的方法内部代码中使用,可以通过this,获得当前对象的属性值,也可以调用自身对象的其它方法 289 | 290 | 291 | 292 | --- 293 | 294 | 本文档 Github : 295 | https://github.com/bushehui/Java_tutorial 296 | 297 | 300 | 301 | 304 | 305 | -------------------------------------------------------------------------------- /ch6_4.md: -------------------------------------------------------------------------------- 1 | [TOC] 2 | 3 | # 继承 4 | 5 | 继承是一种由已有的类创建新类的机制。 6 | 利用继承,我们可以先创建一个拥有共同属性的一般类,根据该一般类再创建具有特殊属性的新类。 7 | 8 | 类具有继承性,子类对父类的继承关系体现了现实世界中特殊和一般的关系。 ==通过继承可以更有效地组织程序结构,明确类间关系,并充分利用已有的类来完成更复杂、深入的开发。== 由继承而得到的类称为子类(subclass), 被继承的类称为父类(或叫超类,superclass)。 9 | 10 | - 直接或间接被继承的类都是父类。 11 | - 子类继承父类的状态和行为,同时也可以修改父类的状态或重写父类的行为,并添加新的状态和行为。 12 | 13 | ==Java中不支多重继承。== 14 | 15 | 16 | ## 创建子类 17 | 18 | Java中的所有类都是**java.lang.Object**类的子类。 19 | 20 | 通过在类的声明中加入__extends__子句来创建一个类的子类,其格式如下: 21 | 22 | ~~~java 23 | class SubClass extends SuperClass{ 24 | …… 25 | } 26 | ~~~ 27 | 28 | 29 | - 把SubClass声明为SuperClass的直接子类。SuperClass为唯一的父类 30 | - 如果SuperClass又是某个类的子类,则SubClass同时也是该类的(间接)子类。 31 | - 子类可以继承父类的成员变量和方法。 32 | - 如果缺省extends子句,则该类为**java.lang.Object**的子类。 33 | - 子类可以继承父类中访问权限设定为**public**、**protected**、**default**的成员变量和方法。 34 | - 但是不能继承访问权限为**private**的成员变量和方法。 35 | 36 | 37 | #### 继承的简单例子 38 | 39 | ~~~java 40 | class Father{ //父类 41 | private int money; 42 | float weight,height; 43 | String head; 44 | 45 | String speak(String s) { 46 | return s ; 47 | } 48 | } 49 | 50 | class Son extends Father{ //子类 51 | String hand, foot; 52 | } 53 | 54 | public class TestExtend { 55 | public static void main(String args[]){ 56 | Son boy=new Son(); 57 | boy.weight=120f; 58 | boy.height=1.8f; 59 | boy.head="一个头"; 60 | boy.hand="两只手"; 61 | boy.foot="两只脚"; 62 | 63 | System.out.println("我是儿子"); 64 | System.out.println("我有:"+boy.hand+"、"+boy.foot+"、"+ boy.head 65 | +"、重"+boy.weight+"、高"+boy.height); 66 | } 67 | } 68 | ~~~ 69 | 70 | 程序运行结果如下: 71 | 72 | >我是儿子 73 | >我有:两只手、两只脚、一个头、重120.0、高1.8 74 | 75 | 76 | ## 成员变量的隐藏和方法的重写 77 | 78 | - 如果子类和父类不在同一个包中,那么,子类可以继承了父类的protected、public修饰的成员变量做为子类的成员变量,并且也可以继承了父类的protected、 public修饰的方法作为子类的方法。 79 | 80 | - 另外子类和父类不在同一个包中,则子类不能继承父类的default变量和default方法。 81 | 82 | 83 | ### 数据成员的隐藏 84 | 数据成员的隐藏是指在子类中重新定义一个与父类中已定义的数据成员名完全相同的数据成员,即子类拥有了两个相同名字的数据成员,一个是继承父类的,另一个是自己定义的。 85 | 当子类要操作继承自父类的同名数据成员时,可使用关键字super引导。 86 | 87 | ### 成员方法的覆盖 88 | 子类可以重新定义与父类格式完全相同(包括方法名、方法形参的个数和类型、方法返回值的类型)的成员方法,实现对父类方法的覆盖。 89 | 90 | - 只有当实例方法能被访问时,才能进行方法覆盖。私有方法不能被覆盖. 91 | - 静态方法(类方法)能被继承,但不能被覆盖。 92 | - 子类在重新定义父类已有的方法时,应保持与父类完全相同的方法名、返回值类型和参数列表,否则就不是方法的覆盖,而是子类定义自己特有的方法,与父类的方法无关。 93 | 94 | 95 | 继承不同包中的类的简例子 96 | 97 | ~~~java 98 | // HouseHold.java 99 | package xing.house; 100 | public class HouseHold { //家类 101 | protected String address; //地址 102 | public String surnname; //姓 103 | 104 | String givenname; //名 105 | 106 | public HouseHold(String add) { address =add;} 107 | protected String getAddress(){return address;} 108 | void setMoney(String newadd) {address=newadd;} 109 | void setAddress(String add){address=add;} 110 | } 111 | ~~~ 112 | 113 | ~~~java 114 | // Mikey.java: 115 | package xing.friend; 116 | import xing.house.HouseHold; 117 | 118 | public class Mikey extends HouseHold { 119 | public Mikey(){ super("Star flight street 110"); } 120 | 121 | public static void main(String args[]){ 122 | Mikey mikey=new Mikey(); 123 | 124 | //mikey.givenname=“Johnson”; //非法 125 | mikey.surnname="Math"; //合法. 126 | mikey.address="Star flight street 110"; //合法. 127 | String m=mikey.getAddress(); //合法 128 | //mikey.setAddress("Star flight street 110"); //非法 129 | System.out.println(mikey.surnname+":"+m); 130 | } 131 | } 132 | ~~~ 133 | 134 | 135 | 136 | ## super关键字 137 | 138 | super表示的是当前对象的直接父类对象,是当前对象的直接父类对象的引用。 139 | 140 | super的使用方法有三种: 141 | 142 | - (1) 访问直接父类隐藏的数据成员,其使用形式如下: 143 | 144 | >super.数据成员 145 | 146 | - (2) 调用直接父类中被覆盖的成员方法,其使用形式如下: 147 | 148 | >super.成员方法(参数) 149 | 150 | - (3)调用直接父类的构造方法,子类可以调用父类声明的构造方法。其使用形式如下: 151 | 152 | >super([参数列表]) 153 | 154 | 155 | **注意**: 156 | 157 | - super 语句必须是子类构造方法的第一条语句。 158 | - 不能在子类中使用父类构造方法名来调用父类构造方法。 159 | - 父类的构造方法不被子类继承。 160 | 161 | 调用父类的构造方法的唯一途径是使用 super 关键字,如果子类中没显式调用,则编译器自动将 super(); 作为子类构造方法的第一条语句。这会形成一个构造方法链。 162 | 163 | 164 | 静态方法中不能使用 super 关键字。 165 | 166 | ## this关键字 167 | 168 | this关键字表示当前对象。 169 | 170 | 可用于: 171 | 172 | - 调用当前类的构造方法,并且必须是方法的第一条语句。如:this(); 调用默认构造方法。this(参数); 调用带参构造方法。 173 | - 限定当前对象的数据域变量。 174 | - 一般用于方法内的局部变量与对象的数据域变量同名的情况。 175 | 如 this.num = num。this.num 表示当前对象的数据域变量 num,而 num 表示方法中的局部变量。 176 | 177 | 178 | 179 | ## 对象的上转型对象 180 | 181 | ### protected关键字 182 | 用**protected**修饰的成员变量可以被三种类所引:该类自身、与它在同一个包中的其它类及在其它包中的该类的子类。 183 | 184 | ### final关键字 185 | 186 | 使用**final**关键字可以定义常量。 187 | 188 | 定义类时,在class关键字前加关键字**final**,表示此类是最终类,不能被其它类继承,不能做父类。 189 | 用final修饰成员方法,表示此方法不能被它的子类覆盖。 190 | 191 | #### final 修饰类中的属性或者变量 192 | 193 | 无论属性是基本类型还是引用类型,final 所起的作用都是变量里面存放的"值"不能变。 194 | 这个值,对于基本类型来说,变量里面放的就是实实在在的值,如 1,"abc" 等。 195 | 而引用类型变量里面放的是个地址,所以用 final 修饰引用类型变量指的是它里面的地址不能变,并不是说这个地址所指向的对象或数组的内容不可以变,这个一定要注意。 196 | 197 | **例如**: 198 | 类中有一个属性是 199 | >final Person p=new Person("name"); 200 | 那么你不能对 p 进行重新赋值,但是可以改变 p 里面属性的值 p.setName('newName'); 201 | 202 | final 修饰属性,声明变量时可以不赋值,而且一旦赋值就不能被修改了。 203 | 对 final 属性可以在三个地方赋值:声明时、初始化块中、构造方法中,总之一定要赋值。 204 | 205 | #### final修饰类中的方法 206 | 作用:可以被继承,但继承后不能被重写。 207 | 208 | #### final修饰类 209 | 作用:类不可以被继承。 210 | 211 | 212 | ### native修饰的方法 213 | 称为本地方法,此方法使用的目的是为了将其它语言(例如,C、C++、FORTRAN、汇编等)嵌入到Java语言中。这样可以充分利用已经存在的其它语言的程序功能模块,避免重复编程。 214 | 215 | 216 | 217 | # 多态性 218 | 219 | 多态(Polymorphism)的意思就是用相同的名字来定义不同的方法。在Java中,普通类型的多态为重载,这就意味着可以使几个不同的方法使用相同的名字,这些方法以参数的个数不同、参数的类型不同等方面来进行区分,以使得编译器能够进行识别。 220 | 221 | 也可以这样讲,重载是同一个方法具有不同的版本,每个版本之间在参数特征方面有差异。==重载是Java实现多态性的方式之一。== 222 | 223 | 例如: 224 | 225 | family()方法可以有三个版本,如下: 226 | 227 | ~~~java 228 | family() { 229 | } 230 | 231 | family(String ch) { 232 | address=ch; 233 | } 234 | 235 | family(String ch,float n) { 236 | address=ch; 237 | pay=n; 238 | } 239 | ~~~ 240 | 241 | 这些方法并存于程序中,编译时,编译器根据实参的类型和个数来区分从而调用那个方法。如果这些方法作为函数或过程同时出现在其它语言的程序中,如C,那将导致灾难性的错误。 242 | 243 | 构造方法重载的例子 244 | 245 | ~~~java 246 | class person { 247 | String name="Johnson"; // 姓名 248 | int age=45; // 年龄 249 | 250 | person(){ } 251 | 252 | person(String a) { 253 | name=a; 254 | } 255 | 256 | person(String a,int b) { 257 | name=a; 258 | age=b; 259 | } 260 | 261 | public voiddisplay(){ 262 | System.out.println("Name="+name+","+"Age="+age); } 263 | } 264 | 265 | public class Poly{ 266 | public static void main(String[] args) { 267 | person ko1=new person(); 268 | person ko2=new person("Mike"); 269 | person ko3=new person("Willian",50); 270 | 271 | ko1.display(); 272 | ko2.display(); 273 | ko3.display(); 274 | } 275 | } 276 | ~~~ 277 | 278 | 279 | 多态是面向对象程序设计语言的一个重要特性,在Java中,可以在同一类或不同类中定义名称相同但是操作不同的多个方法,多态性指的是运行时判断应该执行哪个方法代码的能力,这种能力也叫动态绑定。 280 | 281 | 在Java语言中,多态性分为__编译时多态性__和__运行时多态性__。 282 | 283 | - 编译时的多态性是通过方法重载实现的,Java虚拟机根据传递给方法的参数个数和类型决定调用哪个重载方法。 284 | - 运行时的多态性是Java多态性的最重要的体现,在Java语言的继承关系中,子类对象与父类对象之间有一个重要特性:在任何需要父类对象的地方,都可以使用子类对象来代替,即子类对象可以作为父类对象来使用。一个对象可以通过引用子类的实例来调用子类的方法,通常,方法在父类中定义,在子类中覆盖,子类中调用哪个方法是在运行时决定的,取决于对象的类型,称为运行时的多态性。 285 | 286 | 如果子类重写了父类的方法,那么重写方法的调用原则如下: 287 | 288 | - Java运行时系统根据调用该方法的实例,来决定调用哪个方法。 289 | - 对子类的一个实例,如果子类重写了父类的方法,则运行时系统调用子类的方法;如果子类继承了父类的方法(未重写),则运行时系统调用父类的方法。 290 | 291 | 另外,方法重写时应遵循的原则如下: 292 | 293 | - 改写后的方法不能比被重写的方法有更严格的访问权限。 294 | - 改写后的方法不能比被重写的方法产生更多的异常。 295 | 296 | 进行方法重写时必须遵从这两个原则,否则编译器会指出程序出错。 297 | 298 | 299 | 方法重写的例子 300 | 301 | ~~~java 302 | class Parent{ 303 | public void function(){ 304 | System.out.println("I am in Parent!"); 305 | } 306 | } 307 | 308 | class Child extends Parent{ 309 | private void function(){ 310 | System.out.println("I am in Child!"); 311 | } 312 | } 313 | 314 | public class RTpolyTest{ 315 | public static void main(String args[]){ 316 | Parent pl=new Parent( ); 317 | Parent p2=new Child( ); 318 | 319 | p1.function( ); 320 | p2.function( ); 321 | } 322 | } 323 | ~~~ 324 | 325 | 326 | 编译过程如下: 327 | 328 | >D:\user\chap05>Javac RTpolyTest.java 329 | RTpolyTest.java:8: function() in Child cannot override function() in Parent; attempting to assign weaker access privileges; was public 330 | private void function(){ 331 | ^ 332 | RTpolyTest.java:16: cannot find symbol 333 | symbol : variable p1 334 | location: class RTpolyTest 335 | p1.function( ); 336 | ^ 337 | 2 errors 338 | 339 | 可以看出,该程序中实例p2调用function()方法时会导致访问权限的冲突。 340 | 341 | 342 | 343 | 344 | 345 | 346 | #初始化块 347 | 348 | 初始化块用来和构造方法一起初始化对象。 349 | 初始化块是封装在一对大括号内的语句块,初始化块在类的定义体内,但不能包含在方法体内或构造方法体内。 350 | 351 | 初始化块分为对象(实例)初始化块和静态(类)初始化块。 352 | 353 | 静态数据成员、初始化块和构造方法的执行顺序如下: 354 | 355 | - (1) 当第一次使用类时,首先装载类,初始化静态数据成员,然后执行类的静态初始化块。 356 | - (2) 当使用new运算符创建类的对象时,按下述三个步骤执行: 357 | - ① 调用父类的构造方法(在调用父类的构造方法时,也按照这三个步骤执行)。 358 | - ② 初始化实例数据域,执行对象初始化块。 359 | - ③ 执行构造方法。 360 | 361 | 362 | 370 | 371 | 372 | --- 373 | 374 | 本文档 Github : 375 | https://github.com/bushehui/Java_tutorial 376 | 377 | 380 | 381 | 384 | 385 | -------------------------------------------------------------------------------- /ch6_5.md: -------------------------------------------------------------------------------- 1 | [TOC] 2 | 3 | --- 4 | 5 | **抽象类**与**接口**是java语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予java强大的面向对象的能力。 6 | 他们两者之间对抽象概念的支持有很大的相似,甚至可以互换,但是也有区别。 7 | 8 | --- 9 | 10 | # 抽象类和抽象方法 11 | 12 | ## 抽象类 13 | 14 | 在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的。 15 | 如果一个类没有足够的信息来描述一个具体的对象,而需要其他具体的类来支撑它,那么这样的类我们称它为抽象类。 16 | 比如new Animal(),我们都知道这个是产生一个动物Animal对象,但是这个Animal具体长成什么样子我们并不知道,它没有一个具体动物的概念,所以他就是一个抽象类,需要一个具体的动物,如狗、猫来对它进行特定的描述,我们才知道它长成啥样。 17 | 18 | 抽象类的作用在于将许多有关的类组织在一起,提供一个公共的类,即抽象类,而那些被它组织在一起的具体的类做为它的子类由它派生出来。 19 | 20 | 抽象类体现数据抽象的思想,是实现程序多态性的一种手段。 21 | 抽象类定义了一组抽象的方法,至于这组抽象方法的具体表现形式有派生类来实现。同时抽象类提供了继承的概念,**它的出发点就是为了继承,否则它没有存在的任何意义**。 22 | 所以说定义的抽象类一定是用来继承的,同时在一个以抽象类为节点的继承关系等级链中,叶子节点一定是具体的实现类。 23 | 24 | 25 | Java语言中,用**abstract**关键字来修饰一个类时,这个类叫做抽象类。一个**abstract**类只关心它的子类是否具有某种功能,并不关心该功能的具体实现,功能的具体行为由子类负责实现的。 26 | 27 | 定义抽象类的格式如下: 28 | 29 | ~~~java 30 | abstract class abstractClass{ /* 类定义体 */ } 31 | ~~~ 32 | 33 | 抽象方法是指在返回值类型前加上abstract关键字,且没有方法体。格式如下: 34 | 35 | ~~~java 36 | abstract<返回值类型><抽象方法名>([<形式参数列表>]); 37 | ~~~ 38 | 39 | 例如: 40 | 41 | ~~~java 42 | public abstract class Drawing { 43 | public abstract void drawDot(int x, int y); 44 | public void drawLine(int x1, int y1,int x2, int y2) { 45 | ………… 46 | } 47 | } 48 | ~~~ 49 | 50 | 与**final**类相反,**abstract**类必须被继承,abstract方法必须被重写。 51 | 52 | 当一个类的定义完全表示抽象的概念时,它不应该被实例化为一个对象。例如Java中的Number类就是一个抽象类,它只表示数字这一抽象概念,只有当它作为整数类Integer或实数类Float等的父类时才有意义。 53 | 54 | 定义一个抽象类的格式如下: 55 | 56 | ~~~java 57 | abstract class abstractClass{ /* 类定义体 */ } 58 | ~~~ 59 | 60 | 抽象方法是指在返回值类型前加上**abstract**关键字,且没有方法体。 61 | 格式如下: 62 | 63 | ~~~java 64 | abstract<返回值类型><抽象方法名>([<形式参数列表>]); 65 | ~~~ 66 | 67 | 抽象类中可以包含抽象方法,为所有子类定义一个统一的接口,对抽象方法只需声明,而不需实现,因此它没有方法体。其格式如下: 68 | 69 | ~~~java 70 | abstrac returnType abstractMethod([paramlist)); 71 | ~~~ 72 | 73 | 74 | **例子** 75 | 76 | 定义一个抽象动物类Animal,提供抽象方法叫cry(),猫、狗都是动物类的子类,由于cry()为抽象方法,所以Cat、Dog必须要实现cry()方法。如下: 77 | 78 | ~~~java 79 | public abstract class Animal { 80 | public abstract void cry(); 81 | } 82 | 83 | public class Cat extends Animal{ 84 | 85 | @Override 86 | public void cry() { 87 | System.out.println("猫叫:喵喵..."); 88 | } 89 | } 90 | 91 | public class Dog extends Animal{ 92 | 93 | @Override 94 | public void cry() { 95 | System.out.println("狗叫:汪汪..."); 96 | } 97 | 98 | } 99 | 100 | public class Test { 101 | 102 | public static void main(String[] args) { 103 | Animal a1 = new Cat(); 104 | Animal a2 = new Dog(); 105 | 106 | a1.cry(); 107 | a2.cry(); 108 | } 109 | } 110 | ~~~ 111 | 112 | Output: 113 | 114 | >猫叫:喵喵... 115 | >狗叫:汪汪... 116 | 117 | **抽象类总结规定** 118 | 119 | 1. 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。 120 | 2. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。 121 | 3. 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。 122 | 4. 构造方法,类方法(用static修饰的方法)不能声明为抽象方法。 123 | 5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。 124 | 125 | 126 | ## 抽象方法 127 | 128 | 如果你想设计这样一个类,该类包含一个特别的成员方法,该方法的具体实现由它的子类确定,那么你可以在父类中声明该方法为抽象方法。 129 | abstract关键字同样用来声明抽象方法,抽象方法只包含一个方法名,而没有方法体。 130 | 抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。 131 | 即,用**abstract**来修饰一个方法时,该方法叫做抽象方法。 132 | 133 | ~~~java 134 | public abstract class Employee 135 | { 136 | private String name; 137 | private String address; 138 | private int number; 139 | 140 | public abstract double computePay(); 141 | 142 | //其余代码 143 | } 144 | ~~~ 145 | 146 | 声明抽象方法会造成以下两个结果: 147 | 148 | - 如果一个类包含抽象方法,那么该类必须是抽象类。 149 | - 任何子类必须重写父类的抽象方法,或者声明自身为抽象类。 150 | 151 | 继承抽象方法的子类必须重写该方法。否则,该子类也必须声明为抽象类。 152 | 最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象。 153 | 如果Salary类继承了Employee类,那么它必须实现computePay()方法: 154 | 155 | ~~~java 156 | public class Salary extends Employee 157 | { 158 | private double salary; // Annual salary 159 | 160 | public double computePay() 161 | { 162 | System.out.println("Computing salary pay for " + getName()); 163 | return salary/52; 164 | } 165 | 166 | //其余代码 167 | } 168 | ~~~ 169 | 170 | 171 | 172 | ## 对于抽象类与抽象方法的限制 173 | 174 | - 凡是用**abstract**修饰符修饰的类被称为抽象类,凡是用**abstract**修饰符修饰的成员方法被称为抽象方法; 175 | - 抽象类中可以有零个或多个抽象方法,也可以包含非抽象的方法; 176 | - 抽象类中可以没有抽象方法,但是,有抽象方法的类必须是抽象类; 177 | - 对于抽象方法来说,在抽象类中只指定其方法名及其类型,而不书写其实现代码; 178 | - 抽象类可以派生子类,在抽象类派生的非抽象子类中必须实现抽象类中定义的所有抽象方法; 179 | - 抽象类不能使用new运算符创建对象,但仍可在抽象类中定义构造方法,可由派生类的构造方法调用; 180 | - **abstract**和**final**不能同时修饰一个类; 181 | - **abstract**不能与**private**、**static**、**final**或**native**同时修饰一个方法; 182 | - **abstract**类中不能有**private**的数据成员或成员方法; 183 | - 父类是非抽象类(即具体类),则其子类仍可是抽象类; 184 | - 不能使用new创建抽象类的对象,但抽象类可以当作数据类型使用,如可以声明抽象类的引用,抽象类也可以作为方法的形参类型、返回值类型、数组元素类型等。 185 | 186 | >创建抽象类和抽象方法非常有用,因为他们可以使类的抽象性明确起来,并告诉用户和编译器打算怎样使用他们。抽象类还是有用的重构器,因为它们使我们可以很容易地将公共方法沿着继承层次结构向上移动。(From:Think in java ) 187 | 188 | 189 | 200 | 201 | 202 | **练习** 203 | 204 | 请写出以下这段程序的运行结果: 205 | 206 | ~~~java 207 | abstract class AA{ 208 | abstract void callme( ); 209 | 210 | void metoo( ){ 211 | System.out.println("InsideA's metoo() method"); 212 | } 213 | } 214 | 215 | class BB extends AA{ 216 | void callme( ){ 217 | System.out.println("Inside B's callme() method"); 218 | } 219 | } 220 | 221 | public class AAbstract{ 222 | public static void main(String args[]){ 223 | AA cc=new BB(); //cc为上转型对象 224 | cc.callme(); 225 | cc.metoo(); 226 | } 227 | } 228 | ~~~ 229 | 230 | 231 | 232 | # 接口 233 | 234 | 与C++不同,Java不支持多重继承,而是用接口实现比多重继承更强的功能。 235 | 接口是Java中实现多重继承的唯一途径。 236 | 237 | 接口则把方法的定义和类的层次区分开来,通过它可以在运行时动态地定位所调用的方法。同时,接口可以实现“多重继承”,且一个类可实现多个接口,正是这些机制使得接口提供了比多重继承更简单,更灵活,而且更强健的功能。 238 | 239 | ==接口就是抽象方法声明和常量值的集合。==从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的声明,而没有方法的实现。 240 | 241 | 通过接口使得处于不同层次,甚至互不相关的类可以具有相同的行为。接口其实就是方法定义和常量值的集合。 242 | 243 | 它的优点主要体现在下面几个方面: 244 | 245 | - (1)通过接口可以实现不相关类的相同行为,而不需要考虑这些类之间的层次关系。 246 | - (2)通过接口可以指明多个类需要实现的方法。 247 | - (3)通过接口可以了解对象的交互界面,而不需了解对象所对应的类。 248 | 249 | 接口把方法的定义和类的层次区分开来,通过它可以在运行时动态地定位所调用的方法。同时接口中可以实现“多重继承”,且一个类可以实现多个接口。正是这些机制使得接口提供了比多重继承(如C++等语言)更简单、更灵活、而且更强劲的功能。 250 | 251 | 252 | ## 接口声明 253 | 254 | Java 不支持多继承性,即一个类只能有一个父类。单继承性使得Java类层次简单,易于程序的管理。为了克服单继承的缺点,Java使用了接口,一个类可以实现多个接口。使用关键字**interface**来定义一个接口。接口的定义和类的定义很相似,分为接口声明和接口体两部分。 255 | 256 | 257 | 完整的接口定义格式如下: 258 | 259 | ~~~java 260 | [修饰符] interface 接口名[extends 父接口名列表]{ 261 | //常量数据成员声明 262 | //抽象方法声明 263 | } 264 | ~~~ 265 | 266 | 267 | - 其中public修饰符指明任意类均可以使用这个接口,缺省情况下,只有与该接口定义在同一个包中的类才可以访问这个接口。 268 | - extends子句与类声明中的extends子句基本相同,不同的是一个接口可以有多个父接口,用逗号隔开,而一个类只能有一个父类。 269 | - 子接口继承父接口中所有的常量和方法。 270 | - 通常接口名称以**able**或**ible**结尾,表明接口能完成一定的行为,例如Runnable、Serializable。 271 | 272 | 273 | **注意**: 274 | 275 | - (1) interface是声明接口的关键字,可以把它看成一个特殊类; 276 | - (2) 接口名要求符合Java标识符命名规则; 277 | - (3) 修饰符有两种:public 和默认。public修饰的接口是公共接口,可以被所有的类和接口使用;默认修饰符的接口只能被同一个包中的其它类和接口使用; 278 | - (4) 父接口列表:接口也具有继承性。定义一个接口时可以通过extends关键字声明该接口是某个已经存在的父接口的派生接口,它将继承父接口的所有属性和方法。与类的继承不同的是一个接口可以有一个以上的父接口,它们之间用逗号分隔; 279 | - (5) 常量数据成员声明:常量数据成员前可以有也可省略修饰符。修饰符是public static 和 fina1;接口中的数据成员都是用 final修饰的常量,写法如下: 280 | 281 | ~~~java 282 | 修饰符 数据成员类型 数据成员名=常量值 283 | ~~~ 284 | 285 | 或 286 | 287 | ~~~java 288 | 数据成员类型 数据成员名 = 常量值 289 | ~~~ 290 | 291 | **例如**: 292 | 293 | ~~~java 294 | public final static double PI=3.14159; // double PI=3.14159; 295 | int SUM=100; // public final static int SUM=100; 296 | ~~~ 297 | 298 | - (6) 接口中没有自身的构造方法,所有成员方法都是抽象方法;在接口中只能给出这些抽象方法的方法名、返回值和参数列表,而不能定义方法体,即仅仅规定了一组信息交换、传输和处理的“接口”。格式如下: 299 | 300 | ~~~java 301 | 返回值类型 方法名(参数列表); 302 | ~~~ 303 | 304 | ==Each interface is compiled into a separate bytecode file, just like a regular class.== 305 | 306 | 307 | 308 | ## 接口体 309 | 310 | 接口体中包含常量定义和方法定义两部分。 311 | 其中常量定义部分定义的常量均具有**public**、**static**和**final**属性。 312 | 其格式如下: 313 | 314 | ~~~java 315 | returnType methodName([paramlist]); 316 | ~~~ 317 | 318 | 接口中只能进行方法的声明,而不提供方法的实现,所以,方法定义没有方法体,且用分号(;)结尾,在接口中声明的方法具有**public**和**abstract**属性。另外,如果在子接口中定义了和父接口同名的常量,则父接口中的常量被隐藏。 319 | 320 | **例如**: 321 | 322 | ~~~java 323 | interface Summaryable { 324 | final int MAX=50; // MAX具有public、static、final属性 325 | void printone(float x); 326 | float sum(float x ,float y); 327 | } 328 | ~~~ 329 | 330 | 上面这段程序可以以Summaryable.java来保存,也可以写入其它Java程序中。 331 | 332 | 333 | ## 接口的实现 334 | 335 | 接口定义仅仅是实现某一特定功能的一组功能的对外接口和规范,而不能真正地实现这个功能,这个功能的真正实现是在“继承”这个接口的各个类中完成的,要由这些类来具体定义接口中各抽象方法的方法体。 336 | 337 | 一个类只能继承一个父类,但是可实现多个接口。类定义的完整格式如下: 338 | 339 | ~~~java 340 | [<修饰符>] class <类名>[extends<父类名>] [implements<接口名1>,<接口名2>,……] { 341 | // 类定义体 342 | } 343 | ~~~ 344 | 345 | - 当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。 346 | 347 | **实例** 348 | 349 | ~~~java 350 | /* 文件名 : Animal.java */ 351 | interface Animal { 352 | public void eat(); 353 | public void travel(); 354 | } 355 | ~~~ 356 | 357 | ~~~java 358 | /* 文件名 : MammalInt.java */ 359 | public class MammalInt implements Animal{ 360 | 361 | public void eat(){ 362 | System.out.println("Mammal eats"); 363 | } 364 | 365 | public void travel(){ 366 | System.out.println("Mammal travels"); 367 | } 368 | 369 | public int noOfLegs(){ 370 | return 0; 371 | } 372 | 373 | public static void main(String args[]){ 374 | MammalInt m = new MammalInt(); 375 | m.eat(); 376 | m.travel(); 377 | } 378 | } 379 | ~~~ 380 | 381 | 以上实例编译运行结果如下: 382 | >Mammal eats 383 | >Mammal travels 384 | 385 | 386 | 重写接口中声明的方法时,需要注意以下规则: 387 | 388 | - 类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。 389 | - 类在重写方法时要保持一致的方法名,并且应该保持相同或者相兼容的返回值类型。 390 | - 如果实现接口的类是抽象类,那么就没必要实现该接口的方法。 391 | 392 | 393 | 在实现接口的时候,也要注意一些规则: 394 | 395 | - 一个类可以同时实现多个接口。 396 | - 一个类只能继承一个类,但是能实现多个接口。 397 | - 一个接口能继承另一个接口,这和类之间的继承比较相似。 398 | 399 | 400 | 403 | 404 | - (1)在类中,用**implements**关键字就可以调用接口。一个类可以调用多个接口,这时,在**implements**后用逗号隔开多个接口的名字; 405 | - (2)如果实现某接口的类不是抽象类,则在类的定义体部分必须实现指定接口的所有抽象方法,即为所有抽象方法定义方法体,而且方法头部分应该与接口中的定义完全一致,即有完全相同的返回值和参数列表; 406 | - (3)如果实现某接口的类是抽象类,则它可以不实现该接口所有的方法。 407 | - (4)接口的抽象方法的访问限制符都己指定为**public**,所以类在实现方法时,必须显式地使用**public**修饰符,否则编译系统警告为缩小了接口中定义的方法的访问控制范围。 408 | 409 | ~~~java 410 | class Calculate extends Computer implements Summary,Substractable { 411 | …… 412 | } 413 | ~~~ 414 | 415 | >类Calculate使用了Summary 和Substractable接口,继承了Computer类。 416 | 417 | 418 | 如果一个类使用了某个接口,那么这个类必须实现该接口的所有方法,即为这些方法提供方法体。需要注意的如下: 419 | 420 | - 1)在类中实现接口的方法时,方法的名字,返回类型,参数个数及类型必须与接口中的完全一致。 421 | - 2)接口中的方法被默认是**public**, 所以类在实现接口方法时,一定要用**public**来修饰。 422 | - 3)另外,如果接口的方法的返回类型如果不是**void**的,那么在类中实现该接口方法时,方法体至少要有一个**return**语句。如果是**void**型,类体除了两个大括号外,也可以没有任何语句. 423 | 424 | 425 | 使用多重接口的例子 426 | 427 | ~~~java 428 | // MultInterfaces.java 429 | interface I1 { 430 | abstract void test(int i); 431 | } 432 | 433 | interface I2 { 434 | abstract void test(String s); 435 | } 436 | 437 | public class MultInterfaces implements I1, I2 { 438 | public void test(int i) { 439 | System.out.println("In MultInterfaces.I1.test"); 440 | } 441 | 442 | public void test(String s) { 443 | System.out.println("In MultInterfaces.I2.test"); 444 | } 445 | 446 | public static void main(String[] a) { 447 | MultInterfaces t = new MultInterfaces(); 448 | t.test(42); 449 | t.test("Hello"); 450 | } 451 | } 452 | ~~~ 453 | 454 | ## 接口的继承 455 | - 一个接口能继承另一个接口,和类之间的继承方式比较相似。 456 | - 接口的继承使用extends关键字,子接口继承父接口的方法。 457 | 458 | 下面的Sports接口被Hockey和Football接口继承: 459 | 460 | ~~~java 461 | // 文件名: Sports.java 462 | public interface Sports { 463 | public void setHomeTeam(String name); 464 | public void setVisitingTeam(String name); 465 | } 466 | 467 | // 文件名: Football.java 468 | public interface Football extends Sports { 469 | public void homeTeamScored(int points); 470 | public void visitingTeamScored(int points); 471 | public void endOfQuarter(int quarter); 472 | } 473 | 474 | // 文件名: Hockey.java 475 | public interface Hockey extends Sports { 476 | public void homeGoalScored(); 477 | public void visitingGoalScored(); 478 | public void endOfPeriod(int period); 479 | public void overtimePeriod(int ot); 480 | } 481 | ~~~ 482 | 483 | Hockey接口自己声明了四个方法,从Sports接口继承了两个方法,这样,实现Hockey接口的类需要实现六个方法。 484 | 相似的,实现Football接口的类需要实现五个方法,其中两个来自于Sports接口。 485 | 486 | 487 | - 接口的多继承 488 | 489 | 在Java中,类的多继承是不合法,但接口允许多继承。 490 | 在接口的多继承中extends关键字只需要使用一次,在其后跟着继承接口。 491 | 492 | 如: 493 | 494 | ~~~java 495 | public interface Hockey extends Sports, Event 496 | ~~~ 497 | 498 | 以上的程序片段是合法定义的子接口,与类不同的是,接口允许多继承,而 Sports及 Event 可能定义或是继承相同的方法。 499 | 500 | 501 | 502 | # 接口和抽象类的区别 503 | 504 | 抽象类和接口是java语言中两种不同的抽象概念,他们的存在对多态提供了非常好的支持,虽然他们之间存在很大的相似性。但是对于他们的选择往往反应了您对问题域的理解。只有对问题域的本质有良好的理解,才能做出正确、合理的设计。 505 | 506 | ## 接口与类相似点: 507 | 508 | - 一个接口可以有多个方法。 509 | - 接口文件保存在 .java 结尾的文件中,文件名使用接口名。 510 | - 接口的字节码文件保存在 .class 结尾的文件中。 511 | - 接口相应的字节码文件必须在与包名称相匹配的目录结构中。 512 | 513 | 514 | ## 接口与类的区别: 515 | 516 | Java中所有的类有共同的父类**java.lang.Object**,但接口没有共同的根。 517 | 接口可以当作抽象类使用。 518 | 519 | 抽象类和接口所反映的设计理念是不同的,抽象类所代表的是“is-a”的关系,而接口所代表的是“like-a”的关系。 520 | - 抽象类在java语言中所表示的是一种继承关系,一个子类只能存在一个父类,但是可以存在多个接口。 521 | - 在抽象类中可以拥有自己的成员变量和非抽象类方法,但是接口中只能存在静态的不可变的成员数据,而且它的所有方法都是抽象的。 522 | 523 | 524 | - 接口不能用于实例化对象。(接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。) 525 | - 接口没有构造方法;抽象类中可以有构造方法。 526 | - 接口中所有的方法必须是抽象方法,没有实现部分;抽象类中可以有具体的方法。(由于定义在接口中的所有方法都是抽象方法,接口中可以省略abstract修饰符;但是抽象类中的抽象方法必须用abstract修饰。) 527 | - 接口不能包含成员变量,数据成员必须是必须是常量,默认使用**static** 和 **final** 变量;抽象类中的数据成员可以是变量。 528 | - 接口不是被类继承了,而是要被类实现。 529 | - 接口支持多继承(一个类只能继承一个抽象类,而一个类却可以实现多个接口)。 530 | 531 | 532 | 533 | 534 | 535 | ### 语法层次 536 | 537 | 在语法层次,java语言对于抽象类和接口分别给出了不同的定义。下面已Demo类来说明他们之间的不同之处。 538 | 539 | - 使用抽象类来实现: 540 | 541 | ~~~java 542 | public abstract class Demo { 543 | abstract void method1(); 544 | 545 | 546 | void method2(){ 547 | //实现 548 | } 549 | } 550 | ~~~ 551 | 552 | - 使用接口来实现 553 | 554 | ~~~java 555 | interface Demo { 556 | void method1(); 557 | void method2(); 558 | } 559 | ~~~ 560 | 561 | 抽象类方式中,抽象类可以拥有任意范围的成员数据,同时也可以拥有自己的非抽象方法,但是接口方式中,它仅能够有静态、不能修改的成员数据(但是我们一般是不会在接口中使用成员数据),同时它所有的方法都必须是抽象的。在某种程度上来说,接口是抽象类的特殊化。 562 | 563 | 对子类而言,它只能继承一个抽象类(这是java为了数据安全而考虑的),但是却可以实现多个接口。 564 | 565 | ### 设计层次 566 | 567 | 只有从设计理念的角度才能看出它们的本质所在。一般来说他们存在如下三个不同点: 568 | 569 | - **抽象层次不同** 570 | 抽象类是对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。 571 | 572 | - **跨域不同** 573 | 抽象类所跨域的是具有相似特点的类,而接口却可以跨域不同的类。我们知道抽象类是从子类中发现公共部分,然后泛化成抽象类,子类继承该父类即可,但是接口不同。实现它的子类可以不存在任何关系,共同之处。例如猫、狗可以抽象成一个动物类抽象类,具备叫的方法。鸟、飞机可以实现飞Fly接口,具备飞的行为,这里我们总不能将鸟、飞机共用一个父类吧!所以说抽象类所体现的是一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is-a" 关系,即父类和派生类在概念本质上应该是相同的。对于接口则不然,并不要求接口的实现者和接口定义在概念本质上是一致的, 仅仅是实现了接口定义的契约而已。 574 | 575 | - **设计层次不同** 576 | 对于抽象类而言,它是自下而上来设计的,我们要先知道子类才能抽象出父类,而接口则不同,它根本就不需要知道子类的存在,只需要定义一个规则即可,至于什么子类、什么时候怎么实现它一概不知。比如我们只有一个猫类在这里,如果你这是就抽象成一个动物类,是不是设计有点儿过度?我们起码要有两个动物类,猫、狗在这里,我们在抽象他们的共同点形成动物抽象类吧!所以说抽象类往往都是通过重构而来的!但是接口就不同,比如说飞,我们根本就不知道会有什么东西来实现这个飞接口,怎么实现也不得而知,我们要做的就是事前定义好飞的行为接口。所以说抽象类是自底向上抽象而来的,接口是自顶向下设计出来的。 577 | 578 | 579 | ### 实例 580 | 581 | 我们有一个Door的抽象概念,它具备两个行为open()和close(),此时我们可以定义通过抽象类和接口来定义这个抽象概念: 582 | 583 | - 抽象类 584 | 585 | ~~~java 586 | abstract class Door{ 587 | abstract void open(); 588 | abstract void close(); 589 | } 590 | ~~~ 591 | 592 | - 接口 593 | 594 | ~~~java 595 | interface Door{ 596 | void open(); 597 | void close(); 598 | } 599 | ~~~ 600 | 601 | 至于其他的具体类可以通过使用extends使用抽象类方式定义Door或者Implements使用接口方式定义Door,这里发现两者并没有什么很大的差异。 602 | 603 | 604 | 但是现在**如果我们需要门具有报警的功能**,那么该如何实现呢? 605 | 606 | 607 | #### 解决方案一 608 | 609 | 给Door增加一个报警方法:clarm(); 610 | 611 | ~~~java 612 | abstract class Door{ 613 | abstract void open(); 614 | abstract void close(); 615 | abstract void alarm(); 616 | } 617 | ~~~ 618 | 619 | 或者 620 | 621 | ~~~java 622 | interface Door{ 623 | void open(); 624 | void close(); 625 | void alarm(); 626 | } 627 | ~~~ 628 | 629 | 这种方法违反了面向对象设计中的一个核心原则 **ISP (Interface Segregation Principle)**[^ISP],在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。 630 | 这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变而改变,反之依然。 631 | 632 | [^ISP]: **ISP(Interface Segregation Principle)**:面向对象的一个核心原则。它表明使用多个专门的接口比使用单一的总接口要好。
一个类对另外一个类的依赖性应当是建立在最小的接口上的。
一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。 633 | 634 | #### 解决方案二 635 | 636 | 既然open()、close()和alarm()属于两个不同的概念,那么我们依据ISP原则将它们分开定义在两个代表两个不同概念的抽象类里面,定义的方式有三种: 637 | 638 | - 1、两个都使用抽象类来定义。 639 | - 2、两个都使用接口来定义。 640 | - 3、一个使用抽象类定义,一个是用接口定义。 641 | 642 | 由于java不支持多继承所以第一种是不可行的。后面两种都是可行的,但是选择何种就反映了你对问题域本质的理解。 643 | 644 | 如果选择第二种都是接口来定义,那么就反映了两个问题: 645 | 646 | - 1、我们可能没有理解清楚问题域,AlarmDoor在概念本质上到底是门还报警器。 647 | - 2、如果我们对问题域的理解没有问题,比如我们在分析时确定了AlarmDoor在本质上概念是一致的,那么我们在设计时就没有正确的反映出我们的设计意图。因为你使用了两个接口来进行定义,他们概念的定义并不能够反映上述含义。 648 | 649 | 第三种,如果我们对问题域的理解是这样的: 650 | 651 | - AlarmDoor本质上Door,但同时它也拥有报警的行为功能,这个时候我们使用第三种方案恰好可以阐述我们的设计意图。 652 | - AlarmDoor本质是门,所以对于这个概念我们使用抽象类来定义,同时AlarmDoor具备报警功能,说明它能够完成报警概念中定义的行为功能,所以alarm可以使用接口来进行定义。 653 | 654 | 如下: 655 | 656 | ~~~java 657 | abstract class Door{ 658 | abstract void open(); 659 | abstract void close(); 660 | } 661 | 662 | interface Alarm{ 663 | void alarm(); 664 | } 665 | 666 | class AlarmDoor extends Door implements Alarm{ 667 | void open(){} 668 | void close(){} 669 | void alarm(){} 670 | } 671 | ~~~ 672 | 673 | >这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其实抽象类表示的是"is-a"关系,接口表示的是"like-a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了。 674 | 675 | 676 | --- 677 | 678 | 本文档 Github : 679 | https://github.com/bushehui/Java_tutorial 680 | 681 | 684 | 685 | 688 | 689 | -------------------------------------------------------------------------------- /ch6_6.md: -------------------------------------------------------------------------------- 1 | [TOC] 2 | 3 | --- 4 | 5 | #内部类和匿名类 6 | 7 | ##内部类的定义 8 | 9 | 简单地说,一个类被嵌套定义于另一个类中,称为称为内部类(Inner Classes)或嵌套类。 10 | 在大多数情况下,嵌套类(静态的嵌套类除外)就是内部类(inner class)。包含内部类的类称为外部类。与一般的类相同,内部类具有自己的成员变量和成员方法。通过建立内部类的对象,可以存取其成员变量和调用其成员方法。 11 | 12 | 例如: 13 | 14 | ~~~java 15 | pubic class GroupOne{ 16 | int count; //外部类的成员变量 17 | 18 | public class Student{ //声明内部类 19 | String name; //内部类的成员变量 20 | 21 | public void output(){ //内部类的成员方法 22 | System.out.println(this.name+" "); 23 | } 24 | } 25 | } 26 | ~~~ 27 | 28 | 实际上,Java语言规范对于内部类有如下的规定: 29 | 30 | - 在另一个类或者一个接口中声明一个类。 31 | - 在另一个接口或者一个类中声明一个接口。 32 | - 在一个方法中声明一个类。 33 | - 类和接口声明可嵌套任意深度。 34 | 35 | 36 | ## 内部类特性 37 | 38 | - Java将内部类作为外部类的一个成员,内部类可以调用包含它的外部类的成员变量和成员方法,所以不必把外部类的引用传递给内部类的构造方法。 39 | - 内部类的类名只能用在外部类和内部类自身中,内部类的类名不能与外部类的类名相同。当外部类引用内部类时,须给出完整的名称(外部类名.内部类名)。 40 | - 一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。名称不能与包含它的类名相同。 41 | - 可以使用包含它的外部类的静态成员变量和实例成员变量,也可以使用它所在方法的局部变量。 42 | - 可以声明为public、private或protected,其意义与用在类的其他成员上相同。 43 | - 可以定义为abstract。 44 | - 若被声明为static,就变成了顶层类,不能再使用局部变量。 45 | - 若想在内部类中声明任何static成员,则该内部类必须声明为static。 46 | - __static__型内部类只能访问外部类中的__static__成员。
47 | - 若要访问非static成员,须先创建一个外部类对象,然后通过该对象进行访问。 48 | 49 | 50 | ## 外部类与内部类的访问原则 51 | 52 | - 在外部类中,一般通过一个内部类的对象来访问内部类的成员变量或方法; 53 | - 在内部类中,可以直接访问外部类的所有成员变量和方法(包括静态成员变量和方法、实例成员变量和方法及私有成员变量和方法)。 54 | 55 | **例如**: 56 | 57 | ~~~java 58 | public class GroupTwo { 59 | 60 | private int count; //外部类的私有成员变量 61 | 62 | public class Student { //声明内部类 63 | String name; 64 | 65 | public Student(String n1) { 66 | name=n1; 67 | count++; //存取其外部类的成员变量 68 | } 69 | 70 | public void output(){ 71 | System.out.println(this.name); 72 | } 73 | } 74 | 75 | public void output(){ //外部类的实例成员方法 76 | Student s1=new Student("Johnson"); //建立内部类对象" 77 | s1.output(); //通过s1调用内部类的成员方法 78 | System.out.println("count="+this.count); 79 | } 80 | 81 | public static void main(String args[]){ 82 | GroupTwo g2=new GroupTwo(); 83 | g2.output(); 84 | } 85 | } 86 | ~~~ 87 | 88 | 本例的类GroupTwo中声明了成员变量count、内部类Student、实例方法output和main方法,在内部类Student中声明了构造方法和output方法,构造方法存取了外部类GroupTwo的成员变量count。 89 | 90 | 程序运行结果: 91 | >Johnson 92 | >count=1 93 | 94 | 本例演示嵌套的两个类之间的访问规则,即在外部类GroupTwo中,通过一个内部类Student的对象s1可以引用内部类中的成员;反之,在内部类Student中可以直接引用它的外部类的成员,如count。 95 | 96 | 本例的外部类GroupTwo中有实例方法output(),内部类Student中也有实例方法output(),两者虽然同名,却表达不同含义。使用时,外部类GroupTwo的对象调用GroupTwo的output,如g2.output(),内部类Student的对象调用Student的output,如s1.output()。 97 | 98 | 99 | 100 | 101 | 102 | 103 | ##匿名类 104 | 105 | 有时在定义事件处理代码时,由于代码短小,不必再明确定义一个类,可使用匿名内部类。 106 | 107 | - 匿名内部类是__final__(最终)类,非static类,匿名内部类将类的声明和创建类的实例一步完成。 108 | - 主要应用在事件处理的代码编写中。 109 | - 匿名类是不能有名称的类,所以没办法引用它们。必须在创建时,作为new语句的一部分来声明它们。 110 | 111 | 要采用另一种形式的new语句,如下所示: 112 | 113 | ~~~java 114 | new <类或接口> <类的主体> 115 | ~~~ 116 | 117 | 这种形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。它还创建那个类的一个新实例,并把它作为语句的结果而返回。要扩展的类和要实现的接口是new语句的操作数,后跟匿名类的主体。 118 | 119 | 从技术上说,匿名类可被视为非静态的内部类,所以它们具有和方法内部声明的非静态内部类一样的权限和限制。 120 | 内部和匿名类是Java为我们提供的两个出色的工具。它们提供了更好的封装,结果就是使代码更容易理解和维护,使相关的类都能存在于同一个源代码文件中(这要归功于内部类),并能避免一个程序产生大量非常小的类(这要归功于匿名类)。 121 | 122 | 例如: 123 | 124 | ~~~java 125 | import java.awt.* ; import java.awt.event.*; 126 | public class AnonymousClass{ 127 | private Frame f; 128 | private TextField tf; 129 | 130 | public AnonymousClass(){ 131 | f=new Frame("Inner classes example"); 132 | tf=new TextField(30); 133 | } 134 | 135 | public void launchFrame(){ 136 | Label label=new Label("Click and drag the mouse"); 137 | f.add(label,BorderLayout.NORTH); 138 | f.add(tf,BorderLayout.SOUTH); 139 | 140 | f.addMouseMotionListener(new MouseMotionAdapter(){ 141 | //匿名类开始 142 | public void mouseDragged(MouseEvent e){ 143 | String s="Mouse dragging: 144 | x="+e.getX()+"Y="+e.getY(); 145 | tf.setText(s); 146 | } }); //匿名类结束 147 | 148 | f.setSize(300,200); 149 | f.setVisible(true); 150 | }    151 | public static void main(String args[]){ 152 | AnonymousClass obj=new AnonymousClass(); 153 | obj.launchFrame(); 154 | } 155 | } 156 | ~~~ 157 | 158 | 注意:在使用匿名内部类时,要记住以下几个原则: 159 | 160 | - (1)匿名内部类不能有构造方法; 161 | - (2)匿名内部类不能定义任何静态成员、方法和类。 162 | - (3)匿名内部类不能是__public__, __protected__, __private__, __static__。 163 | - (4)只能创建匿名内部类的一个实例。
164 | 一个匿名内部类一定是在__new__的后面,用其隐含实现一个接口或实现一个类。
165 | 因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。 166 |
内部类只能访问外部类的静态变量或静态方法。 167 | - (5)当在匿名类中用__this__时,这个__this__则指的是匿名类或内部类本身。
168 | 这时如果要使用外部类的方法和变量,则应该加上外部类的类名 169 | 170 | 171 | #包(package) 172 | 173 | 包(package)是Java提供的文件(即公共类)的组织方式。
174 | 一个包对应一个文件夹,一个包中可以包括许多类文件。
175 | 包中还可以再有子包,称为包等级。 176 | 177 | ##包的作用有四个: 178 | 179 | - (1) 定位类:具有相似功能的类可以放置在同一个包中,这样可以很容易地查找定位类。 180 | - (2) 避免命名冲突:在开发由其他程序员共享的可复用类时,会发生命名冲突,可以把类放在不同包中,通过包名引用类可以避免命名冲突。 181 | - (3) 可以方便地分发软件。 182 | - (4) 控制类之间的访问 183 | 184 | 注意: 185 | 186 | - 包是一个类名空间,同一个包中的类和接口不能重名,不同包中的类可以重名。 187 | - 根据Java的命名规则,包名均为小写字母。 188 | - 类之间的访问控制是通过类修饰符来实现的,若类修饰符为__public__,则表明该类不仅可供同一包中的类访问,也可以被其他包中的类访问。 189 | - 若类无修饰符,则表明该类仅供同一包中的类访问。 190 | - Java的包等级和Windows的文件组织方式完全相同,只是表示方法不同。 191 | 192 | 193 | 194 | ##包的定义 195 | 196 | 包的定义就是将源程序文件中的接口和类纳入指定的包。 197 | 198 | 一般情况下,Java源程序由四部分组成: 199 | 200 | - (1) 一个包(package)定义语句(可选项)。其作用是将本源文件中的接口和类纳入指定包。
源文件中若有包说明语句,必须是第一个语句; 201 | - (2) 若干个(import)语句(可选项)。其作用是引入本源文件中所需要使用的包; 202 | - (3) 一个__public__的类声明。
在一个源文件中只能有一个__public__类; 203 | - (4) 若干个属于本包的类声明(可选)。 204 | 205 | 包的定义语句格式: 206 | 207 | >package 包名1[.包名2[.包名3…]]; 208 | 209 | - 创建包就是在当前文件夹下创建一个子文件夹,存放这个包中包含的所有类和接口的.class文件。 210 | - 语句中的符号“.”代表了目录分隔符,说明这个语句创建了两个文件夹。 211 | 212 | ==习惯上,包名都用小写字母。== 213 | 214 | Java规定,如果一个Java文件中有package语句,那么package语句必须写在Java源程序的第一行,该行前只能有空格和注释行。
215 | Package语句在每个Java源程序中只能有一条,一个类只能属于一个包。 216 | 217 | 例如: 218 | 219 | ~~~java 220 | package cn.edu.hebiace; 221 | ~~~ 222 | 223 | 定义了包,语句中的包名分隔符“.”相当于目录分隔符。
224 | 使用package语句指定一个源文件中的类属于一个特定的包。 225 | 226 | Java要求包名与文件系统的目录结构一一对应。
227 | 对于名为cn.edu.hebiace的包,必须创建一个如图所示的目录结构。 228 | 229 | ![](fig/packagedir.png) 230 | 231 | 若源文件中未使用package语句创建包,则该源文件中的接口和类位于Java的无名包中(无名包又称默认包,指当前目录),会把源文件中的类存储在当前目录(即存放Java源文件的目录)下。 232 | 233 | ==无名包中的类不能被其他包中的类引用和复用== 234 | 235 | 236 | ##设置类路径 237 | 238 | 包是一种组织代码的有效手段,包名指出了程序中需要使用的".class"文件的所在之处。
239 | 另一个能指明".class"文件所在的位置是环境变量CLASSPATH。 240 | 241 | 对于Java Application程序,还可以通过为Java解释器设置参数来指定类文件路径。 242 | 243 | 例如, 244 | 对于JDK中的Java解释器java.exe,有开关参数-classpath; 245 | 246 | 假设当需要解释执行的test.class文件不在当前目录而在e盘的TEMP目录下时,可以使用如下的命令行语句: 247 | 248 | >java -classpath e:\temp Test 249 | 250 | 来运行这个程序 251 | 252 | 253 | ##包的使用 254 | 255 | Java提供了丰富的标准类来帮助程序设计者更方便快捷地编写程序,这些标准类组成了类包,主要有: 256 | 257 | - java.lang 258 | - java.applet 259 | - java.io 260 | - java.net 261 | - java.util 262 | - java.awt 263 | - java.awt.image 264 | - java.awt.peer 265 | 266 | 使用Swing组件进行GUI设计,使用javax.swing包中的类 267 | 268 | ==除了java.lang之外,其余类包都不是java语言所必须的。==
269 | 若要使用,必须进行包的导入。 270 | 271 | 将类组织成包的目的是为了更好地利用包中的类。 272 | 通常一个类只能引用与它在同一个包中的类。 273 | 274 | 如果需要使用其它包中的public类,则可以使用如下的几种方法。 275 | 276 | - (1) 在引入的类前加包名
277 | 例如: 278 | 279 | ~~~java 280 | pack1.pack2.Format.format(23.4533,2); 281 | ~~~ 282 | 283 | - (2) 单类型导入(single-type-import)
284 | 例如上面的语句在程序开始处增加了: 285 | 286 | ~~~java 287 | import pack1.pack2.Format; 288 | ~~~ 289 | 290 | 语句之后,就可以直接写成: 291 | 292 | ~~~java 293 | Format.format(23.4533,2); 294 | ~~~ 295 | 296 | - (3) 按需类型导入(type-import-on-demand) 297 | 298 | ~~~java 299 | import pack1.pack2.*; 300 | ~~~ 301 | 302 | 303 | # 类型转换和instanceof运算符 304 | 305 | 基本数据类型可以进行强制或自动类型转换,也可以把一个类的对象转换为继承链中的另一个对象。 306 | 将子类的实例转换为父类的实例总是可行的,因为子类的实例也是父类的实例。例如 307 | 308 | ~~~java 309 | Shapes[0] = point; 310 | ~~~ 311 | 312 | 等价于 313 | 314 | ~~~java 315 | Shapes[0] = (Shape)point; 316 | ~~~ 317 | 318 | 把父类对象转换为子类对象时,必须使用强制类型转换,为使转换成功,必须确保转换的对象是子类的一个实例。 319 | 320 | 进行转换时确保该对象是另一个类的实例,可以利用instanceof运算符来完成。如: 321 | 322 | ~~~java 323 | Point point1 = new Point(); 324 | // Point是Circle的父类 325 | if(point1 instanceof Circle) { 326 | Circle circle1 = (Circle)point1; 327 | } 328 | ~~~ 329 | 330 | ## 父类对象与和子类对象的转化需要注意如下的原则: 331 | 332 | - (1) 子类对象可以被视为是其父类的一个对象; 333 | - (2) 父类对象不能当成是其某一个子类的对象; 334 | - (3)如果一个方法的形式参数是父类对象,那么调用这个方法时,可以使用子类对象作为实际参数; 335 | - (4) 如果父类对象引用指向的实际是一个子类对象,那么这个父类对象的引用可以用强制类型转换转化成子类对象的引用,但在转换之前要使用instanceof运算符进行判断。 336 | 337 | 338 | ## Cloneable接口 339 | 340 | 接口包含常量和抽象方法,但是Cloneable接口例外,Cloneable接口定义如下: 341 | 342 | ~~~java 343 | public interface Cloneable{ 344 | } 345 | ~~~ 346 | 347 | Cloneable接口的定义体为空,定义体为空的接口称为标记接口。Java系统要求,可复制的类需要实现Cloneable接口,利用定义在Object类中的clone()方法,可以复制可复制类的对象。 348 | 349 | --- 350 | 351 | 本文档 Github : 352 | https://github.com/bushehui/Java_tutorial 353 | 354 | 357 | 358 | 361 | 362 | -------------------------------------------------------------------------------- /ch7.md: -------------------------------------------------------------------------------- 1 | --- 2 | title : 多线程 3 | --- 4 | 5 | [TOC] 6 | 7 | 8 | # 多线程编程技术 9 | 10 | ## 进程与线程的基本概念 11 | 12 | ### 进程 13 | 14 | 随着计算机的飞速发展,个人计算机上的操作系统也纷纷采用多任务和分时设计,将早期只有大型计算机才具有的系统特性带到了个人计算机系统中。一般可以在同一时间内执行多个程序的操作系统都有进程的概念。 15 | 16 | - 一个进程就是一个执行中的程序,而每一个进程都有自己独立的一块内存空间、一组系统资源。 17 | - 进程是操作系统中正在执行的不同应用程序的一个实例,操作系统把不同的进程分离开来 18 | - 每一个进程的内部数据和状态都是完全独立的。 19 | 20 | 21 | ### 线程 22 | 23 | - 线程是操作系统分配处理器时间的基本单元,每个线程都维护异常处理程序、调度优先级和一组系统用于在调度该线程前保存线程上下文的结构 24 | 25 | - 每个应用程序域都是用单个线程启动的(应用程序的入口点main()方法),应用程序域中的代码可以创建附加应用程序域和附加线程 26 | 27 | #### 一个线程由三个主要部分组成 28 | 29 | - 一个虚拟处理机 30 | - CPU执行的代码 31 | - 代码操作的数据 32 | 33 | 代码可以或不可以由多个线程共享,这时数据是独立的。两个线程如果执行同一个类的实例代码,则它们可以共享相同的代码。 34 | 类似地,数据可以或不可以由多个线程共享,这时代码是独立的。两个线程如果共享对一个公共对象的存取,则它们可以共享相同的数据。 35 | 36 | ![](fig/thread.png) 37 | 38 | #### 优点: 39 | 40 | - 多线程编程简单,效率高(能直接共享数据和资源,多进程不能) 41 | - 适合于开发服务程序(如Web服务,聊天服务等) 42 | - 适合于开发有多种交互接口的程序(如聊天程序的客户端,网络下载工具) 43 | - 减轻编写交互频繁、涉及面多的程序的困难(如监听网络端口) 44 | - 程序的吞吐量会得到改善(同时监听多种设备,如网络端口、串口、并口以及其他外设) 45 | - 有多个处理器的系统,可以并发运行不同的线程(否则,任何时刻只有一个线程在运行) 46 | 47 | #### 线程的缺点 48 | 49 | - 多线程处理可解决用户响应性能和多任务的问题,但同时引入了资源共享和同步问题等问题 50 | 51 | 54 | 55 | ### 线程与进程的区别 56 | 57 | 线程与进程相似,是一段完成某个特定功能的代码,是程序中单个顺序的流控制。 58 | 59 | 但与进程不同的是,同类的多个线程共享一块内存空间和一组系统资源,而线程本身的数据通常只有微处理器的寄存器数据,以及一个供程序执行时使用的堆栈。 60 | 所以系统在产生一个线程,或者在各个线程之间切换时,负担要比进程小的多,正因如此,线程被称为轻负荷进程(light-weight process)。一个进程中可以包含多个线程。一个线程是一个程序内部的顺序控制流。主要区别如下: 61 | 62 | 1. 进程:每个进程都有独立的代码和数据空间(进程上下文) ,进程切换的开销大。 63 | 2. 线程:轻量的进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。 64 | 3. 多进程:在操作系统中,能同时运行多个任务程序。 65 | 4. 多线程:在同一应用程序中,有多个顺序流同时执行。 66 | 67 | 68 | ## 在Java语言中,创建、启动、暂停、中断和终止线程 69 | 70 | 应用程序运行时,运行环境调用应用程序的入口点(main()方法)时,将创建应用程序主线程 71 | 72 | 74 | 75 | 主线程以外的线程一般称之为工作线程 76 | 77 | ### 创建线程有两种方式 78 | 79 | - 继承java.lang.Thread类 80 | - 实现java.lang.Runnable接口 81 | 82 | 可以根据具体的应用环境进行选择。参见JDK API 83 | 84 | #### 继承Thread类 85 | 86 | - 该方法比较简单,主要是通过继承java.lang.Thread类,并覆盖Thread类的run()方法来完成线成的创建。 87 | - Thread类是一个具体的类,即不是抽象类,该类封装了线程的行为。 88 | - 要创建一个线程,程序员必须创建一个从Thread类导出的新类。 89 | - Thread类中有两个最重要的函数run()和start()。 90 | 91 | 96 | 97 | ##### 通过继承Thread类创建新线程的大致步骤如下: 98 | 99 | - 创建一个将在主线程外执行的函数,即类的方法,用于执行新线程要执行的逻辑操作 100 | - 在主线程(main()方法)中创建一个步骤1中所创建的派生类的实例。例如: 101 | 102 | ~~~java 103 | MyThread thread1 = new MyThread() 104 | ~~~ 105 | 106 | - 调用步骤2中创建的Thread的实例的start()方法,以启动新线程。例如: 107 | 108 | ~~~java 109 | thread1.start() 110 | ~~~ 111 | 112 | 113 | 114 | #####通过继承Thread类创建和启动新线程示例 115 | 116 | ~~~java 117 | public class MyThread extends Thread 118 | { // count变量用于统计打印的次数并共享变量 119 | private static int count = 0; 120 | public MyThread(String name){super(name);} 121 | public static void main(String[] args){// main方法开始 122 | MyThread p = new MyThread("t1"); // 创建一个线程实例 123 | p.start(); // 执行线程 124 | // 主线程main方法执行一个循环 125 | for (int i = 0; i < 5; i++) { 126 | count++; 127 | // 主线程中打印count+“main”变量的值,并换行 128 | System.out.println(count + ": main"); 129 | } 130 | } 131 | 132 | public void run() 133 | {// 线程类必须有的run()方法 134 | for (int i = 0; i < 5; i++) { 135 | count++; 136 | System.out.println(count + ":" + this.getName()); 137 | } 138 | } 139 | } 140 | ~~~ 141 | 142 | ##### Thread类有很多重载的构造方法: 143 | 144 | - Thread() 145 | - Thread(Runnable target) 146 | - Thread(Runnable target, String name) 147 | - Thread(String name) 148 | - Thread(ThreadGroup group, Runnable target) 149 | - Thread(ThreadGroup group , Runnable target, String name) 150 | - Thread(ThreadGroup group , String name) 151 | 152 | 参数target是线程执行的目标对象,即线程执行的代码;group是线程所在的组;name是线程的名字。 153 | 154 | #### 实现Runnable接口 155 | 156 | 该方法通过生成实现java.lang.Runnable接口的类。 157 | 该接口只定义了一个方法run(),所以必须在新类中实现它。 158 | 但是Runnable接口并没有任何对线程的支持,我们还必须创建Thread类的实例,这一点通过Thread类的构造函数 159 | 160 | ~~~java 161 | public Thread(Runnable target); 162 | ~~~ 163 | 164 | 来实现。 165 | 166 | ##### 通过实现Runnable接口创建新线程的大致步骤 167 | 168 | - 创建一个实现Runnable接口的派生类,并重写继承的方法run(),用于执行新线程要执行的逻辑操作 169 | - 在主线程(main()方法)中创建一个步骤1中所创建的派生类的实例 170 | - 在主线程(main()方法)中,使用步骤2中所创建的对象实例作为参数,创建一个Thread对象实例 171 | - 调用步骤2中创建的Thread实例的Start()方法,以启动新线程 172 | 173 | 174 | 175 | ##### 通过实现Runnable接口创建和启动新线程示例 176 | 177 | ~~~java 178 | public class MyThread2 implements Runnable{ 179 | int count=1,number; 180 | public MyThread2(int i){ 181 | number=i; 182 | System.out.println("创建线程"+number); 183 | } 184 | public void run(){ 185 | while(true){ 186 | System.out.println(“线程”+number+“计数 "+count); 187 | if(++count==3) 188 | return; 189 | } 190 | } 191 | 192 | public static void main(String args[]){ 193 | for(int i=0;i<3;i++) 194 | { 195 | Thread p =new Thread(new MyThread2(i+1)); 196 | p.start(); 197 | } 198 | } 199 | } 200 | ~~~ 201 | 202 | new MyThread2(i+1) 对象是实现了Runnable接口的实体,作为Thread构造方法的形参。 203 | 204 | 205 | ##### 通过匿名类 206 | 207 | 可以直接通过匿名类的方式创建新线程 208 | 209 | - 在主线程(main()方法)中,使用一个实现Runnable接口的匿名派生类对象为参数,创建一个Thread对象实例 210 | - 调用步骤1中创建的Thread实例的Start()方法,以启动新线程 211 | 212 | 213 | 214 | 215 | 216 | ## 线程状态和生命周期 217 | 218 | - 线程是动态的,具有一定的生命周期,分别经历从创建、执行、阻塞直到消亡的过程。 219 | - 在每个线程类中都定义了用于完成实际功能的run方法,这个run方法称为线程体(Thread Body)。 220 | - 按照线程体在计算机系统内存中的状态不同,可以将线程分为创建(new)、就绪(runnable)、运行、阻塞(blocked)和死亡(dead)5个状态, 221 | 222 | ![](fig/thread2.png) 223 | 224 | 247 | 248 | ### 就绪状态和阻塞状态转换 249 | 250 | 在状态转换的各个过程中,最关键也是最复杂的就是就绪状态和阻塞状态转换的过程。 251 | Java 提供了大量方法来支持阻塞。 252 | 253 | #### sleep() 方法: 254 | sleep()允许指定以毫秒为单位的一段时间作为参数,它使得线程在指定的时间内进入阻塞状态,不能得到CPU 时间,指定的时间一过,线程重新进入可执行状态。 255 | 典型地,sleep()被用在等待某个资源就绪的情形:测试发现条件不满足后,让线程阻塞一段时间后重新测试,直到条件满足为止。 256 | 257 | #### suspend()和resume()方法: 258 | 两个方法配套使用,suspend()使得线程进入阻塞状态,并且不会自动恢复,必须其对应的resume()被调用,才能使得线程重新进入可执行状态。 259 | 典型地,suspend()和resume()被用在等待另一个线程产生的结果的情形:测试发现结果还没有产生后,让线程阻塞,另一个线程产生了结果后,调用resume()使其恢复。 260 | 261 | 在线程运行过程中调用sleep方法后,该线程在不释放占用资源的情况下停止运行指定的睡眠时间。 262 | 时间到达后,线程重新由JVM线程调度器进行调度和管理。 263 | 而调用suspend方法后,线程将释放占用的所有资源,由JVM调度转入临时存储空间,直至应用程序调用resume方法恢复线程运行。 264 | 265 | #### wait()和notify()方法: 266 | 两个方法配套使用,wait()使得线程进入阻塞状态,它有两种形式,一种允许指定以毫秒为单位的一段时间作为参数,另一种没有参数,前者当对应的notify()被调用或者超出指定时间时线程重新进入就绪,后者则必须对应的notify()被调用。 267 | 268 | 269 | ##### wait()方法的语义是: 270 | 当一个线程执行了该方法,则该线程进入阻塞状态,同时让出同步对象的互斥锁,并自动进入互斥对象的等待队列。 271 | 272 | ##### notify()方法的语义是: 273 | 当一个线程执行了该方法,则拥有该方法的互斥对象的等待队列中的第一个线程被唤醒,同时自动获得该互斥对象的互斥锁,并进入就绪状态等待调度。 274 | 275 | #### void jion() 276 | 等待指定的线程运行结束 当线程不活动时,jion()才会返回 277 | #### void jion(long timeout) 278 | 等待指定的线程运行结束,但不超过指定的超时值 279 | #### yield(): 280 | 可以用来使具有相同优先级的线程获得执行的机会。如果具有相同优先级的其它线程是可运行的,yield()将把调用线程放到可运行池中并使另一个线程运行。如果没有相同优先级的可运行进程,yield()什么都不做。 281 | 282 | 283 | ### 抢先式调度 284 | 285 | 线程调度器按线程的优先级高低选择高优先级线程(进入运行中状态)执行,同时线程调度是抢先式调度,即如果在当前线程执行过程中,一个更高优先级的线程进入可运行状态,则这个线程立即被调度执行。 286 | 抢先式调度又分为:时间片方式和独占方式。 287 | 288 | #### 时间片方式 289 | 290 | 当前活动线程执行完当前时间片后,如果有其他处于就绪状态的相同优先级的线程,系统会将执行权交给其他就绪态的同优先级线程;当前活动线程转入等待执行队列,等待下一个时间片的调度。 291 | 292 | #### 独占方式 293 | 294 | 当前活动线程一旦获得执行权,将一直执行下去,直到执行完毕或由于某种原因主动放弃CPU,或者是有一高优先级的线程处于就绪状态。 295 | #### 线程会放弃CPU 296 | 297 | 下面几种情况下,当前线程会放弃CPU: 298 | 299 | 1. 线程调用了yield() 或sleep() 方法主动放弃; 300 | 2. 由于当前线程进行I/O 访问,外存读写,等待用户输入等操作,导致线程阻塞;或者是为等候一个条件变量,以及线程调用wait()方法; 301 | 3. 抢先式系统下,由高优先级的线程参与调度;时间片方式下,当前时间片用完,由同优先级的线程参与调度。 302 | 303 | 304 | ## 线程优先级和线程调度 305 | 306 | Java将每个线程都分配一个优先级,优先级用正整数设置,通常为1-10。 307 | 默认情况下,创建的线程最初被分配的优先级是5,数字越大表明线程的级别越高。 308 | 309 | Thread类中声明了3个定义线程优先级范围的静态最终常量: 310 | 311 | - Thread.MIN_PRIORITY(1、最低) 312 | - Thread.NORM_PRIORITY(5、普通) 313 | - Thread.MAX_PRIORITY(10、最高) 314 | 315 | 通过线程对象的实例方法setPriority(int newPriority),即可以设定线程对象的优先级 316 | 317 | 318 | 319 | ### Daemon线程 320 | 321 | 在Java中比较特殊的线程是被称为守护(Daemon)线程的低级别线程。 322 | 这个线程具有最低的优先级,用于为系统中的其它对象和线程提供服务。 323 | 324 | 将一个用户线程设置为守护线程的方式是在线程对象创建之前调用线程对象的setDaemon方法。 325 | 典型的守护线程例子是JVM中的系统资源自动回收线程,它始终在低级别的状态中运行,用于实时监控和管理系统中的可回收资源。 326 | 327 | 333 | 334 | ~~~java 335 | public class TestThreadPriority extends Thread { 336 | String strMessage; 337 | 338 | public TestThreadPriority(String strPara) { 339 | strMessage = strPara; 340 | } 341 | 342 | public static void main(String[] args) { 343 | TestThreadPriority testThreadPriority1 = new TestThreadPriority("Thread1"); 344 | testThreadPriority1.setPriority(Thread.MIN_PRIORITY); 345 | 346 | testThreadPriority1.start(); 347 | TestThreadPriority testThreadPriority2 = new TestThreadPriority("Thread2"); 348 | testThreadPriority2.setPriority(Thread.NORM_PRIORITY); 349 | testThreadPriority2.start(); 350 | TestThreadPriority testThreadPriority3 = new TestThreadPriority("Thread3"); 351 | testThreadPriority3.setPriority(Thread.MAX_PRIORITY); 352 | testThreadPriority3.start(); 353 | } 354 | 355 | public void run() { 356 | for(int i=0; i<3;i++) 357 | System.out.println(this.getName()+"is running!"); 358 | } 359 | } 360 | 361 | ~~~ 362 | 363 | 364 | ## 线程互斥 365 | 366 | ### 问题的提出 367 | 368 | 类Acount代表一个银行账户。其中变量balance是该账户的余额。 369 | 370 | ~~~java 371 | public class Acount{ 372 | double balance; 373 | public Acount(double money){ 374 | balance = money; 375 | System.out.println("Totle Money: "+balance); 376 | } 377 | } 378 | ~~~ 379 | 380 | 下面我们定义一个线程,该线程的主要任务是从Acount中取出一定数目的钱。 381 | 382 | ~~~java 383 | public class AcountThread extends Thread { 384 | Acount acount; 385 | int delay; 386 | public AcountThread(Acount acount,int delay) { 387 | this.acount =acount; 388 | this.delay = delay; 389 | } 390 | 391 | public void run(){ 392 | if(acount.balance >= 100){ 393 | try{ 394 | sleep(delay); 395 | acount.balance = acount.balance - 100; 396 | System.out.println("withdraw 100 successful!"); 397 | }catch(InterruptedException e) { 398 | } 399 | } 400 | else 401 | System.out.println("withdraw failed!"); 402 | } 403 | 404 | public static void main(String[] args) { 405 | Acount acount = new Acount(100); 406 | AcountThread acountThread1 = new AcountThread(acount,1000); 407 | AcountThread acountThread2 = new AcountThread(acount,0); 408 | acountThread1.start(); 409 | acountThread2.start(); 410 | } 411 | } 412 | 413 | ~~~ 414 | 415 | 运行结果如下: 416 | 417 | >Totle Money: 100.0 418 | >withdraw 100 successful! 419 | >withdraw 100 successful! 420 | 421 | - 该结果非常奇怪,因为尽管账面上只有100元,但是两个取钱线程都取得了100元钱,也就是总共得到了200元钱。出错的原因在哪里呢? 422 | - 由于线程1在判断满足取钱的条件后,被线程2打断,还没有来得及修改余额。因此线程2也满足取钱的条件,并完成了取钱动作。从而使共享数据balance的完整性被破坏。 423 | 424 | 425 | 426 | ### 临界资源 427 | 428 | 在并发程序设计中,对多线程共享的资源或数据成为临界资源,而把每个线(进)程中访问临界资源的那一段代码段成为临界代码段。 429 | 通过为临界代码段设置信号灯,就可以保证资源的完整性,从而安全地访问共享资源 430 | 431 | 432 | 为了实现这种机制,Java语言提供以下两方面的支持: 433 | 434 | 1. 为每个对象设置了一个“互斥锁”标记。该标记保证在每一个时刻,只能有一个线程拥有该互斥锁,其它线程如果需要获得该互斥锁,必须等待当前拥有该锁的线程将其释放。该对象成为互斥对象。因此,java中的每一个对象都是互斥对象. 435 | 436 | 2. 为了配合使用对象的互斥锁,Java语言提供了保留字synchronized.其基本用法如下: 437 | 438 | ~~~java 439 | synchronized(互斥对象){ 440 | 临界代码段 441 | } 442 | ~~~ 443 | 444 | ### 修改后的程序 445 | 446 | ~~~java 447 | class Semaphore{} 448 | public class AcountThread2 extends Thread { 449 | Acount acount; 450 | int delay; 451 | Semaphore semaphore; 452 | public AcountThread2(Acount acount,int delay,Semaphore semaphore) { 453 | this.acount =acount; 454 | this.delay = delay; 455 | this.semaphore = semaphore; 456 | } 457 | 458 | public void run(){ 459 | synchronized (semaphore) { 460 | if (acount.balance >= 100) { 461 | try { 462 | sleep(delay); 463 | acount.balance = acount.balance - 100; 464 | System.out.println("withdraw 100 successful!"); 465 | } 466 | catch (InterruptedException e) { 467 | } 468 | } 469 | else 470 | System.out.println("withdraw failed!"); 471 | } 472 | } 473 | 474 | public static void main(String[] args) { 475 | Acount acount = new Acount(100); 476 | Semaphore semaphore = new Semaphore(); 477 | AcountThread2 acountThread1 = new AcountThread2(acount,1000,semaphore); 478 | AcountThread2 acountThread2 = new AcountThread2(acount,0,semaphore); 479 | acountThread1.start(); 480 | acountThread2.start(); 481 | } 482 | } 483 | 484 | ~~~ 485 | 486 | 487 | 488 | ### 线程同步 489 | 当多个线程同时调用单个对象的方法时,一个线程可能会中断另一个线程正在执行的任务,使该对象处于一种无效状态,因此这些调用必须进行同步处理 490 | 491 | 在实际应用中,多个线程之间不仅需要互斥机制来保证对共享数据的完整性,而且有时需要多个线程之间互相协作,按照某种既定的步骤来共同完成任务。 492 | 493 | #### 生产-消费者模型 494 | 一个典型的应用模型。其约束条件为: 495 | 496 | 1. 生产者负责产品,并将其保存到仓库中; 497 | 2. 消费者从仓库中取得产品。 498 | 3. 由于库房容量有限,因此只有当库房还有空间时,生产者才可以将产品加入库房;否则只能等待。只有库房中存在满足数量的产品时,消费者才能取走产品,否则只能等待。 499 | 500 | 501 | ![](fig/thread3.png) 502 | 503 | 实际应用中的许多例子都可以归结为该模型。 504 | 如在操作系统中的打印机调度问题,库房的管理问题等。 505 | 506 | 为了研究该问题,我们仍然以前面的存款与取款问题作为例子,假设存在一个账户对象(仓库)及两个线程:存款线程(生产者)和取款线程(消费者),并对其进行如下的限制; 507 | 508 | 1. 只有当账户上的余额balance=0时,存款线程才可以存进100元;否则只能等待; 509 | 2. 只有当账户上的余额balance=100时,取款线程才可以取走100元;否则只能等待。 510 | 511 | 利用wait()方法和notify()方法,上面的程序修改如下 512 | 513 | ~~~java 514 | public class Acount4 { 515 | double balance; 516 | public Acount4(){ 517 | balance = 0; 518 | System.out.println("Totle Money: "+balance); 519 | } 520 | public synchronized void withdraw(double money){ 521 | if(balance == 0) 522 | try{ 523 | wait(); 524 | }catch(InterruptedException e){ 525 | } 526 | balance = balance - money; 527 | System.out.println("withdraw 100 success"); 528 | notify(); 529 | } 530 | 531 | public synchronized void deposite(double money){ 532 | if (balance != 0) 533 | try { 534 | wait(); 535 | } 536 | catch (InterruptedException e) { 537 | } 538 | balance = balance + money; 539 | System.out.println("deposite 100 success"); 540 | notify(); 541 | } 542 | } 543 | 544 | public class AcountThread3 extends Thread { 545 | Acount2 acount; 546 | public AcountThread3(Acount2 acount) { 547 | this.acount = acount; 548 | } 549 | public void run(){ 550 | acount.withdraw(100); 551 | } 552 | public static void main(String[] args) { 553 | Acount2 acount = new Acount2(100); 554 | AcountThread3 acountThread31 = new AcountThread3(acount); 555 | AcountThread3 acountThread32 = new AcountThread3(acount); 556 | acountThread31.start(); 557 | acountThread32.start(); 558 | } 559 | } 560 | 561 | ~~~ 562 | 563 | 568 | 569 | 570 | 571 | 572 | 576 | 577 | 578 | 579 | ### 线程死锁 580 | 581 | #### 哲学家用餐问题 582 | 583 | 我们可以想象,如果每个哲学家都彬彬有礼,并且高谈阔论,轮流吃饭,则这种融洽的气氛可以长久地保持下去。但是可能出现这样一种情景:当每个人都拿起自己左手边的筷子,并同时去拿自己右手边的筷子时,会发生什么情况:五个人每人拿着一支筷子,盯着自己右手边的那位哲学手里的一支筷子,处于僵持状态。这就是发生了“线程死锁”。 584 | 585 | 需要指出的事,线程死锁并不是必然会发生,在某些情况下,可能会非常偶然。 586 | 587 | 线程死锁只是系统的一种状态,该状态出现的机会可能会非常小,因此简单的测试往往无法发现。 588 | 遗憾的是Java语言也没有有效的方法可以避免或检测死锁,因此我们只能在程序设计中尽力去减少这种情况的出现。 589 | 590 | 一般来说,要出现死锁必须同时具备四个条件。 591 | 因此,如果能够尽可能地破坏这四个条件中的任意一个,就可以避免死锁的出现。 592 | 593 | 1. 互斥条件。即至少存在一个资源,不能被多个线程同时共享。如在哲学家问题中,一支筷子一次只能被一个哲学家使用。 594 | 2. 至少存在一个线程,它拥有一个资源,并等待获得另一个线程当前所拥有的资源。如在哲学家聚餐问题中,当发生死锁时,至少有一个哲学家拿着一支筷子,并等待取得另一个哲学家拿着的筷子。 595 | 3. 线程拥有的资源不能被强行剥夺,只能有线程资源释放。如在哲学家问题中,如果允许一个哲学家之间可以抢夺筷子,则就不会发生死锁问题。 596 | 597 | ### 线程死锁是并发程序设计中可能遇到的问题 598 | 599 | 它是指程序运行中,多个线程竞争共享资源时可能出现的一种系统状态:线程1拥有资源1,并等待资源2,而线程2拥有资源2,并等待资源3,…,以此类推,线程n拥有资源n-1,并等待资源1。在这种状态下,各个线程互不相让,永远进入一种等待状态。 600 | 601 | 602 | ### 线程间通信 603 | 604 | 为了解决死锁的问题,Java引入了线程间通信的通信机制:wait()、notify()和notifyAll() 605 | 606 | 线程之间的通讯问题是指线程之间相互传递信息,这些信息包括数据、控制指令等。我们前面举例中数据共享也是线程的一种通信方式。 607 | 608 | 此外,java语言还提供了线程之间通过管道来进行通信的方式。其结构表示。管道通信具有如下特点: 609 | 610 | - 管道是单向的。 611 | 一个线程充当发送者,另一个线程充当接收者。如果需要建立双向通信,可以通过建立多个管道解决。 612 | 613 | - 管道通信是面向连接的。 614 | 因此在程序设计中,一方线程必须建立起对应的端点,由另一方线程来建立连接。 615 | 616 | - 管道中的信息是严格按照发送的顺序进行传送的。 617 | 因此接收受方收到的数据和发送方在顺序上完全一致。 618 | 619 | ~~~java 620 | import java.io.*; 621 | class SenderThread extends Thread{ 622 | PipedWriter pipedWriter; 623 | public SenderThread( ){ 624 | pipedWriter = new PipedWriter( ); 625 | } 626 | public PipedWriter getPipedWriter( ){ 627 | return pipedWriter; 628 | } 629 | public void run( ){ 630 | for (int i =0; i<5;i++){ 631 | try{ 632 | pipedWriter.write(i); 633 | }catch(IOException e){ 634 | } 635 | System.out.println("Send: "+i); 636 | } 637 | } 638 | } 639 | 640 | 641 | ~~~ 642 | 643 | ##练习 644 | 645 | 1. 创建线程有哪两种方法?并进行比较,说明各自特点。 646 | 2. 简述线程的生命周期。 647 | 3. 设计一个程序,每隔一秒显示一次系统时间。 648 | 4. 设计一个程序,该程序包含两个线程,一个线程做冒泡排序,一个线程做插入排序。 649 | 5.设计一个生产者-消费者程序。对一个对象(堆栈)进行操作,生产者是一个压入线程,它不断向堆栈中压入数据;消费者是一个弹出线程,它不断从堆栈中弹出数据。设计的程序应避免共享资源带来的问题,使两个线程能够正确地对堆栈对象进行操作。 650 | 651 | 652 | --- 653 | 654 | 本文档 Github : 655 | https://github.com/bushehui/Java_tutorial 656 | 657 | 658 | 661 | 662 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | -------------------------------------------------------------------------------- /ch8.md: -------------------------------------------------------------------------------- 1 | --- 2 | title : GUI程序设计 3 | --- 4 | 5 | [TOC] 6 | 7 | #GUI程序设计 8 | 9 | Java图形用户界面由各种可视化组件构成,如窗口、文本框、下拉列表框、按钮等。 10 | 11 | ##GUI Class Hierarchy 12 | 13 | ###AWT 14 | AWT(Abstract Window ToolKit,抽象窗口工具包)是最原始的Java GUI工具包,提供了一套与本地图形界面进行交互的接口。 15 | 16 | - AWT包括一些基本的GUI组件、布局管理器和事件的工具包,可以用于构建图形化用户界面的Java应用程序 17 | - AWT中的图形函数与操作系统所提供的图形函数之间有着一一对应的关系 18 | 19 | ###Swing 20 | 21 | Swing是在AWT的基础上构建的一套新的图形界面系统,它提供了AWT所能够提供的所有功能,并且对AWT的功能进行了大幅度的扩充,提供了大量复杂的组件(例如表、树、进度条等)。 22 | 23 | - Swing组件是用100%的Java代码来实现的,因此在一个平台上设计的树形控件可以在其他平台上使用 24 | Swing是AWT的扩展。 25 | - Swing使用了AWT的事件模型和支持类,例如Colors、Images和Graphics 26 | - 一般情况下,建议使用Swing组件构建图形用户界面应用程序 27 | 28 | 在javax.swing包中,Swing组件都是AWT的Container类的直接子类或间接子类 29 | Swing组件中定义了4种顶层容器(窗体):JFrame、JApplet、JDialog和JWindow 30 | 31 | ![](fig/swing.png) 32 | 33 | ![](fig/swing2.png) 34 | 35 | ####Swing中的类主要分为两类 36 | 37 | #####JComponent及其子类,称为Swing组件。 38 | 39 | Swing组件分为两类: 40 | 41 | - 一类是Swing自带的基础Swing组件,包括如图所示的JComponent及其全部子类。 42 | - 另一类是自定义组件,程序员可以通过继承JComponent及其子类创建自定义的Swing组件。 43 | 44 | Swing组件中有一部分组件具有图形外观能在图形界面上与用户进行交互,称为可视化组件,例如JButton、JLabel、JTextField等。 45 | 46 | Swing组件中的另外一些组件没有图形外观,称为非可视化组件。非可视化组件通常需要与可视化组件相结合,共同完成特定的图形功能。 47 | 48 | ####顶层容器(container)。 49 | 所谓容器,是指该Swing类能够包含其他的容器或Swing组件。 50 | 顶层容器是容器中最顶层的,不能被其他容器所包含,但可以在其上放置其他的非顶层容器和Swing组件。 51 | 顶层容器包含JApplet、JDialog、JFrame和JWindow及其子类。 52 | 例如JFrame是描述窗体的顶层容器,在JFrame之上可以放置按键(JButton)、表格(JTable)、树形组件(JTree)等Swing组件,但不能在按键(JButton)之上放置JApplet或者JDialog及其子类。 53 | 54 | 除了顶层容器,Swing中JComponent及其子类都具有容器的能力,都能够包含其他的容器或者Swing组件,但其显示效果是有差异的。 55 | 例如JPanel(面板)是一种专用的轻量级容器类,在JPanel之上可以放置其他容器或者Swing组件,同时JPanel也可以被加入到其他的中间容器和顶层容器中,但JPanel不能包含顶层容器。 56 | 原则上JButton也具有容器的能力,可以在JButton上包含其他的Swing组件,但是否能将添加的Swing组件显示出来,则是不确定的 57 | 58 | 容器(Container)也是一个类,实际上是Component的子类,因此容器本身也是一个组件,具有组件的所有性质,但是它的主要功能是容纳其它组件和容器。 59 | 60 | 1)容器可以简化图形化界面的设计,以整体结构来布置界面。 61 | 62 | 2)所有的容器都可以通过add()方法向容器中添加组件。 63 | 64 | Swing容器层次结构 65 | ![](fig/swing3.png) 66 | 67 | #####容器分类 68 | 69 | - 顶层容器窗体 70 | JFrame; JWindow; JApplet; 71 | 对话框JDialog(JOptionPane) 72 | 73 | - 中间层容器 74 | 面板JPanel; 滚动窗格JScrollPane, JScrollBar; 拆分窗格JSplitPane; 索查标签窗格JTabbedPane 75 | - 特殊容器 76 | 内部窗体JInternalFrame; 分层窗格JLayeredPane; 根窗格JRootPane 77 | 78 | 79 | ![](fig/swing4.png) 80 | 81 | 82 | #####MVC模式 83 | 84 | Swing中的类在设计时采用了模型、视图、控制器(Model View Controller,MVC)模式作为每个组件的基本设计。 85 | MVC模式是GUI程序设计中比较常见的一种设计方法,因此理解MVC模式不仅有利于学习Swing,更有助于设计GUI程序。 86 | MVC模式将GUI组件拆分为模型、视图、控制器三个基本要素,每一个要素都对组件的表现起着至关重要的作用。 87 | 88 | ![](fig/swingmvc.png) 89 | 90 | ######模型(Model) 91 | 92 | - 包含每个组件的数据状态,不同类型的组件有不同的模型。 93 | - 什么是组件的数据状态呢?例如滚动条组件(JScrollBar)的数据状态就包含滚动条的当前位置、最大值、最小值以及滚动条的宽度等。这些数据信息就是滚动条组件的模型。 94 | 95 | ######视图(View) 96 | 97 | - 是组件在屏幕上的表现形式。 98 | - 由于Java是跨平台的语言,同一个组件在不同的平台上的显示是不相同的,在不同的外观风格下也是不相同的。为了让Java的GUI程序也应该做到“Write once,run anywhere”,Swing组件依据组件的模型和当前所处的显示环境进行组件绘制。 99 | 100 | ######控制器(Controller) 101 | 102 | - 控制组件如何与事件进行交互。 103 | - 事件的形式有多种,例如鼠标单击、获得或者失去焦点、键盘点击等。当这些事件发生时,控制器根据事件的类型,决定组件如何响应 104 | 105 | #####顶层容器类 106 | 107 | 108 | 109 | ######框架窗口(Jframe) 110 | 111 | 窗口是最基本的用户界面元素。框架窗口是一种窗体,其中带有边框、标题栏及用于关闭和最大/最小化窗口的图标等。 112 | 在GUI的应用程序中,一般至少应使用一个框架窗口。 113 | 通常将框架窗口简称为窗口。 114 | 115 | 使用JFrame类显示一个简单的窗体 116 | ~~~java 117 | import javax.swing.JFrame; 118 | public class JFrameDemo { 119 | public static void main(String[] args) { 120 | JFrame frame=new JFrame(); //JFrame实例化 121 | frame.setSize(300,300); //设置窗体大小为300x300 122 | frame.setLocation(400, 400); //设置窗体显示位置在(400,400) 123 | frame.setTitle(“JFrameDemo”); //设置窗体标题为 124 | //设置关闭按键的默认操作 125 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 126 | frame.setVisible(true); //显示窗体 127 | } 128 | } 129 | ~~~ 130 | 131 | 使用继承方式创建窗体 132 | 133 | ~~~java 134 | import javax.swing.JFrame; 135 | public class MyFrame extends JFrame { 136 | public MyFrame() 137 | { 138 | setSize(300,300); //设置窗体大小为300x300 139 | setLocation(400, 400); //设置窗体显示位置在(400,400) 140 | setTitle("MyFrame"); //设置窗体标题为MyFrame 141 | //设置关闭按键的默认操作 142 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 143 | } 144 | public static void main(String[] args) { 145 | MyFrame myFrame=new MyFrame(); //MyFrame实例化 146 | myFrame.setVisible(true); //显示窗体 147 | } 148 | } 149 | ~~~ 150 | 151 | JFrame作为容器 152 | 153 | ~~~java 154 | import java.awt.FlowLayout; 155 | import javax.swing.JButton; 156 | import javax.swing.JFrame; 157 | public class ButtonFrame extends JFrame{ 158 | private JButton button=new JButton("按键"); 159 | public ButtonFrame() 160 | { 161 | setSize(300,300); 162 | setLocation(400, 400); 163 | setTitle("ButtonFrame"); 164 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 165 | setLayout(new FlowLayout()); //设置布局 166 | add(button); //添加按键 167 | } 168 | public static void main(String[] args) { 169 | ButtonFrame frame=new ButtonFrame(); 170 | frame.setVisible(true); 171 | } 172 | } 173 | 174 | ~~~ 175 | 176 | 177 | ######JDialog、JWindow和JApplet 178 | 179 | - JDialog是创建对话框的顶层容器类。JDialog的使用方式以及其所包含的方法和属性与JFrame都有许多类似。但JDialog创建的对话框与JFrame创建的窗体在外观上是不同的,例如对话框没有最大化和最小化按键。在GUI编程时可以根据需要选择使用JDialog还是JFrame。 180 | 181 | - JWindow也可以创建一个窗体容器,但是JWindow创建的窗体没有标题栏,没有最大化、最小化按键。在某些GUI应用中,可能需要编写这种不带修饰的窗体,或者用户希望用自己编写的标题栏、最大化、最小化按键来替换Windows自带的窗体风格,此时就可以选择通过创建JWindow来实现这些窗体效果。JWindow的使用方式以及其所包含的方法和属性与JFrame也基本类似。 182 | 183 | - Applet是一种能够嵌入到网页中执行的Java图形程序。JApplet是创建这种程序的顶层容器 。 184 | 185 | 186 | #####布局管理 187 | 188 | Swing提供了setLocation(),setSize(),setBounds() 等布局方法,但Swing的组件中存在一个默认的布局管理器,因此这些设置方法都会失效。如果需要设置组件大小或位置,则应取消该容器的布局管理器,方法为调用容器的setLayout方法,并将布局管理器设置为null。 189 | 190 | 相对于基于布局管理器的布局方式在对组件的大小和位置的控制上较为灵活,但这种布局方式会导致平台相关,在不同的平台上可能产生不同的显示效果。如果想让GUI程序以一致的外观在不同的平台上运行,则需要采用基于布局管理器的布局方式。 191 | 192 | ######无布局管理器的布局 193 | 194 | ~~~java 195 | import java.awt.FlowLayout; 196 | import javax.swing.JButton; 197 | import javax.swing.JFrame; 198 | import javax.swing.JLabel; 199 | import javax.swing.JTextField; 200 | public class AbsoluteLayoutDemo extends JFrame { 201 | private JButton button=new JButton("JButton");; 202 | private JTextField textField=new JTextField("JTextField "); 203 | public AbsoluteLayoutDemo() 204 | { 205 | setSize(300, 300); 206 | setLocation(400, 400); 207 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 208 | //设置布局管理为null 209 | setLayout(null); 210 | 211 | //设置按键的位置为(20,20),宽100,高20 212 | button.setLocation(20, 20); 213 | button.setSize(100, 20); 214 | add(button); 215 | //设置输入框的位置为(20,50),宽200,高100 216 | textField.setBounds(20,50,200,100); 217 | add(textField); 218 | } 219 | public static void main(String[] args) { 220 | AbsoluteLayoutFrame frame=new AbsoluteLayoutFrame(); 221 | frame.setVisible(true); 222 | } 223 | } ~~~ 224 | 225 | ######FlowLayout 226 | 227 | 容器采用FlowLayout布局其组件的放置规律是从左到右、从上到下进行放置,如果容器足够宽,第一个组件先添加到容器中第一行的最左边,后续的组件依次添加到上一个组件的右边,如果当前行已放置不下该组件,则放置到下一行的最左边。 当容器的大小发生变化时,用FlowLayout管理的组件会发生变化,其变化规律是:组件的大小不变,但是相对位置会发生变化。 228 | 229 | ~~~java 230 | import java.awt.FlowLayout; 231 | import javax.swing.JButton; 232 | import javax.swing.JFrame; 233 | public class FlowLayoutDemo extends JFrame { 234 | private JButton button1 = new JButton("First Button"); 235 | private JButton button2 = new JButton("Second Button"); 236 | private JButton button3 = new JButton("Third Button"); 237 | private JButton button4 = new JButton("Fourth Button"); 238 | public FlowLayoutDemo() { 239 | setSize(300, 150); 240 | setLocation(400, 400); 241 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 242 | //设置布局方式为FlowLayout 243 | setLayout(new FlowLayout()); 244 | 245 | //添加按键,注意设置布局方式之后任何对 246 | / /组件进行设置的方法,例如setSize、 247 | //setLocation等都会失效 248 | add(button1); 249 | add(button2); 250 | add(button3); 251 | add(button4); 252 | } 253 | public static void main(String arg[]) { 254 | FlowLayoutDemo frame = new FlowLayoutDemo(); 255 | frame.setVisible(true); 256 | } 257 | } 258 | 259 | ~~~ 260 | 261 | ######BorderLayout 262 | 263 | BorderLayout布局管理器把容器分成5个区域:North,South,East,West和Center,每个区域只能放置一个组件。 264 | 如果使用了BorderLayout布局,当容器的大小发生变化,其变化规律为:组件的相对位置不变,大小发生变化。例如容器变高了,则North、South区域不变,West、Center、East区域变高;如果容器变宽了,West、East区域不变,North、Center、South区域变宽。不一定所有的区域都有组件,如果四周的区域(West、East、North、South区域)没有组件,则由Center区域去补充。 265 | 266 | ~~~java 267 | import java.awt.GridLayout; 268 | import javax.swing.JButton; 269 | import javax.swing.JFrame; 270 | public class GridlayoutDemo extends JFrame { 271 | private JButton button1 = new JButton("First Button"); 272 | private JButton button2 = new JButton("Second Button"); 273 | private JButton button3 = new JButton("Third Button"); 274 | private JButton button4 = new JButton("Fourth Button"); 275 | public GridlayoutDemo() { 276 | setSize(300, 300); 277 | setLocation(400, 400); 278 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 279 | 280 | //设置布局方式为GridLayout,2行,2列 281 | setLayout(new GridLayout(2,2)); 282 | //添加组件时不需要设置组件所在行、列 283 | add(button1); 284 | add(button2); 285 | add(button3); 286 | add(button4); 287 | } 288 | public static void main(String arg[]) { 289 | GridlayoutDemo frame = new GridlayoutDemo(); 290 | frame.setVisible(true); 291 | } 292 | } 293 | 294 | ~~~ 295 | 296 | ######其他布局管理器 297 | 298 | - CardLayout布局管理器能够帮助用户处理两个以至更多的成员共享同一显示空间,它把容器分成许多层,每层的显示空间占据整个容器的大小,但是每层只允许放置一个组件,当然每层都可以利用容器来实现复杂的用户界面。 299 | - GridBagLayout生成的布局管理器与GridLayout一样是使用网格来进行布局管理的,所不同之处在于GridBagLayout可以通过类GridBagConstraints 来控制容器内各个组件的大小。 300 | - SpringLayout是在JDK1.4中加入的布局管理器,该布局管理器功能强大,布局灵活,能够模拟其他布局管理器的布局。 301 | - JDK1.6加入了GroupLayout。它是以Group(组)为单位来管理布局,也就是把多个组件(如:JLable、JButton)按区域划分到不同的Group(组),再根据各个Group(组)相对于水平轴(Horizontal)和垂直轴(Vertical)的排列方式来管理。 302 | 303 | 304 | 305 | #####事件处理 306 | 307 | - Swing采用了委托(delegation)事件模型,也叫授权事件模型来处理系统发生的各类事件。授权事件模型是JDK1.1开始采用的事件处理模型,而在JDK1.1之前Java采用的是层次(hierarchal)模型 。 308 | - 在授权事件模型中,主要包含了三个对象:事件:发生在用户界面上的用户交互行为所产生的一种效果。事件源:产生事件的对象。事件监听器:接受事件并对其进行处理的对象。 309 | - 组件作为事件源可以触发事件,一个事件源注册一个或多个事件监听器。当特定事件发生时,事件被委托到具体的事件监听器进行处理。 310 | 311 | ######委托事件模型具有优点 312 | 313 | - 事件对象只传给注册的监听器,不会意外地被其他组件或上层容器捕获和处理。 314 | - 可以实现过滤器的功能,只监听和处理感兴趣的事件。 315 | - 实现了将事件源和事件监听器分开处理的功能。 316 | 317 | ######编写事件处理程序 318 | 319 | 下面我们以JButton组件的单击事件为例,说明如何编写事件处理程序。 320 | 321 | - 编写事件监听器 322 | 按键点击事件可以由实现了ActionListener接口的类进行处理。因此首先需要编写一个实现了ActionListener接口的类。 323 | ActionListener接口中只有有唯一的方法: 324 | 325 | >public void actionPerformed( ActionEvent e) 326 | 327 | 参数ActionEvent e是对应点击事件的对象。 328 | 通过调用该对象的方法可以获取事件的相关属性,例如调用getSource方法将返回事件发生的对象。程序员需要为该方法编写特定的事件处理代码。 329 | 330 | - 为按键注册事件监听程序 331 | 为JButton注册事件监听程序,需要调用JButton的addActionListener方法: 332 | 333 | >public void addActionListener (ActionListener handler) 334 | 335 | 该方法能够接受一个实现了ActionListener接口的类。如果要对按键注册多个监听器,则需要编写多个事件监听器,并多次调用addActionListener方法,将每个监听器都注册到组件中。 336 | 337 | 338 | ~~~java 339 | import java.awt.BorderLayout; 340 | import java.awt.event.ActionEvent; 341 | import java.awt.event.ActionListener; 342 | import javax.swing.JButton; 343 | import javax.swing.JFrame; 344 | public class EventDemo extends JFrame{ 345 | JButton button=new JButton("press me"); 346 | public EventDemo() { 347 | setSize(300,300); 348 | setLocation(400, 400); 349 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 350 | //设置按键事件,使用了匿名类 351 | button.addActionListener(new ActionListener(){ 352 | //获取被点击的按键 353 | public void actionPerformed(ActionEvent e) { JButton clickedButton=(JButton) e.getSource(); 354 | //改变被点击按键的标题 355 | clickedButton.setText("I have been pressed"); 356 | } 357 | }); 358 | setLayout(new BorderLayout()); 359 | add(button,BorderLayout.NORTH); 360 | } 361 | public static void main(String[] args) { 362 | EventDemo frame=new EventDemo(); 363 | frame.setVisible(true); 364 | } 365 | } 366 | 367 | ~~~ 368 | 369 | #####事件类 370 | 371 | 在委托事件模型中,事件既是基础,又是联系各个部分的桥梁。首先,组件作为事件源产生事件,不同类型的组件会产生不同类型的事件。事件发生后,事件被传递给对应事件监听器中实现的事件处理方法,并且在事件中,包含着用户传递给系统的交互信息,如文本框中的输入内容等。不同类型的事件由不同的Java类来表示,基类是java.util.EventObject, 所有的事件都是从它继承而来的 。 372 | 373 | ![](fig/swingevents.png) 374 | 375 | ######事件监听器 376 | 377 | 接收事件并对事件做出相应反映的对象称为事件监听器。java.awt.event包中按照不同的事件类型定义了多个监听器接口,每类事件都有对应的事件监听器接口,接口中定义了事件发生时可调用的方法。 378 | 379 | ![](fig/swingevents2.png) 380 | 381 | ######事件适配器 382 | 383 | 采用实现监听器接口的方法时,不管你是否对相关事件进行处理,都必须实现所有这些方法,比如,你实现了WindowListener接口,你可能只对处理窗口关闭的windowClosing方法感兴趣,但是你不得不实现其余六个方法。事件适配器就是为了解决这一问题的。 384 | 385 | 使用适配器,只须重写需要实现的方法,无关方法不用实现,这简化了程序代码。同监听器不同的是,监听器是一个接口,而适配器是一个类,要使用适配器,就必须继承对应的适配器类。 386 | 387 | ######键盘与鼠标事件 388 | 389 | 键盘事件和鼠标事件是GUI程序中最常见的两类事件。 390 | 与键盘事件相关的监听器是KeyListener,与鼠标事件相关的监听器包括:MouseListener、MouseMotionListener和MouseWheelListener。 391 | 为了处理相应的事件,需要调用相应的addXXXlistener方法,添加相应的事件监听器。 392 | 393 | 键盘和鼠标事件还有对应的适配器KeyAdapter和MouseAdapter。 394 | 395 | 键盘事件处理 396 | 397 | ~~~java 398 | import java.awt.BorderLayout; 399 | import java.awt.event.KeyAdapter; 400 | import java.awt.event.KeyEvent; 401 | import javax.swing.JFrame; 402 | import javax.swing.JLabel; 403 | public class KeyEventDemo extends JFrame{ 404 | JLabel label=new JLabel("按下了按键:"); 405 | public KeyEventDemo() { 406 | setSize(300,300); 407 | setLocation(400, 400); 408 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 409 | this.addKeyListener(new KeyAdapter(){ 410 | public void keyPressed(KeyEvent event) { 411 | switch(event.getKeyCode()) 412 | { 413 | case KeyEvent.VK_UP: 414 | label.setText("按下了按键:UP"); 415 | break; 416 | 417 | case KeyEvent.VK_DOWN: 418 | label.setText("按下了按键:DOWN"); 419 | break; 420 | case KeyEvent.VK_LEFT: 421 | label.setText("按下了按键:LEFT"); 422 | break; 423 | case KeyEvent.VK_RIGHT: 424 | label.setText("按下了按键:RIGHT"); 425 | break; 426 | default: 427 | label.setText("按下了按键:"+event.getKeyChar()); 428 | } 429 | } 430 | }); 431 | setLayout(new BorderLayout()); 432 | add(label,BorderLayout.CENTER); 433 | } 434 | } 435 | 436 | ~~~ 437 | 438 | 鼠标事件处理 439 | 440 | ~~~java 441 | import java.awt.BorderLayout; 442 | import java.awt.event.MouseAdapter; 443 | import java.awt.event.MouseEvent; 444 | import java.awt.event.MouseWheelEvent; 445 | import javax.swing.JFrame; 446 | import javax.swing.JLabel; 447 | public class MouseEventDemo extends JFrame{ 448 | JLabel label=new JLabel(""); 449 | public MouseEventDemo() { 450 | setSize(300,300); 451 | setLocation(400, 400); 452 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 453 | this.addMouseListener(new MouseAdapter(){ 454 | public void mouseClicked(MouseEvent event) 455 | { 456 | label.setText("鼠标在"+event.getX()+","+event.getY()+"进行了点击"); 457 | } 458 | }); 459 | 460 | this.addMouseMotionListener(new MouseAdapter(){ 461 | public void mouseMoved(MouseEvent event) { 462 | label.setText("鼠标移动到了"+event.getX()+","+event.getY()); 463 | } 464 | }); 465 | this.addMouseWheelListener(new MouseAdapter(){ 466 | public void mouseWheelMoved(MouseWheelEvent event) { 467 | label.setText("鼠标滚轮进行了滚动"); 468 | } 469 | }); 470 | setLayout(new BorderLayout()); 471 | add(label,BorderLayout.CENTER); 472 | } 473 | public static void main(String[] args) { 474 | MouseEventDemo frame=new MouseEventDemo(); 475 | frame.setVisible(true); 476 | } 477 | } 478 | 479 | ~~~ 480 | 481 | --- 482 | 483 | 本文档 Github : 484 | https://github.com/bushehui/Java_tutorial 485 | 486 | 489 | 490 | 493 | 494 | 495 | 496 | 497 | -------------------------------------------------------------------------------- /ch9.md: -------------------------------------------------------------------------------- 1 | --- 2 | title : JDBC与数据库访问 3 | --- 4 | 5 | [TOC] 6 | 7 | 8 | # JDBC与数据库访问 9 | 10 | ## 关系数据库和SQL 11 | 12 | ### 数据库概述 13 | 14 | 数据库是一个有组织的数据集合,它由一个或多个表组成。每一个表中都存储了对一类对象的数据描述。 15 | 数据库管理系统(database management system,DBMS)以一种与数据库格式一致的方式,提供了存储和组织数据的机制。 16 | 17 | 当前最流行的数据库是关系型数据库,它是将数据表示为表的集合,通过建立简单表之间的关系来定义结构的一种数据库。 18 | 数据库中的表按照行和列的形式来存储信息。行表示关系型数据库中的记录,列表示数据属性。 19 | 比较著名的关系数据库管理系统有Oracle、Sybase、DB2、MySQL、Microsoft SQL Server等。 20 | 21 | 22 | ### 数据库系统 23 | 24 | - 数据库系统由数据库、数据库管理软件和应用软件组成 25 | 26 | ![](fig/dbms.png) 27 | 28 | - 一个应用程序可以访问多个数据库系统 29 | 30 | ![](fig/dbms2.png) 31 | 32 | 33 | ### SQL 34 | 35 | SQL是一个国际化标准语言,几乎所有关系型数据库都用SQL语言执行数据查询和操纵。 36 | 37 | #### 理解SQL语句时要注意几点: 38 | 39 | - SQL语言中的语句都是独立执行的,无上下文联系; 40 | - 每条语句都有自己的主关键字,语句中可包含若干子句; 41 | - SQL语句本身不区分大小写。为突出语句格式,下面例子中保留字采用大写。 42 | 43 | 44 | #### SQL基本命令 45 | 46 | ##### 建表语句 47 | 48 | - 格式: 49 | 50 | ~~~sql 51 | CREATE TABLE table_name (column1 type [not] null,…) 52 | ~~~ 53 | 54 | - 功能: 55 | 在当前数据库中创建一张名为的table_name表格结构。 56 | 57 | ##### 删除表 58 | 59 | - 格式: 60 | 61 | ~~~sql 62 | DROP table_name 63 | ~~~ 64 | 65 | - 功能: 66 | 在当前数据库中删除名为table_name的表。 67 | 68 | ##### 查询语句 69 | 70 | - 格式: 71 | 72 | ~~~sql 73 | SELECT col1,col2,...,coln FROM table_name [WHERE condition_expression] 74 | ~~~ 75 | 76 | - 功能: 77 | 从数据库表中检索满足条件的记录。WHERE子句是可选项,它可以包含<、 >、 <=、 >=、 =、<>和LIKE运算符。 78 | LIKE运算符用于带有通配符百分号(%)和下划线(_)的模式匹配。 79 | 80 | - 例: 81 | 82 | ~~~sql 83 | SELECT * FROM account WHERE accountNumber='1280316401' 84 | ~~~ 85 | 86 | ##### 插入语句 87 | 88 | - 格式: 89 | 90 | ~~~sql 91 | INSERT INTO table_name [(col1,col2,...,coln)] VALUES(v1,v2,...,vn) 92 | ~~~ 93 | 94 | - 功能: 95 | 在表table_name中插入一条记录,各列的值依次分别为v1、v2、…、vn等,若某列的列名未给,则值为NULL。 96 | 97 | - 注意: 98 | (1)如果所有的列名都未给,则在Values中必须依次给出所有列的值。 99 | (2)给出的值的类型必须与对应的列的类型相一致。 100 | 101 | ##### 更新语句 102 | 103 | - 格式: 104 | 105 | ~~~sql 106 | UPDATE table_name SET col1=v1 [,col2=v2,...,coln=vn][WHERE condition_expression] 107 | ~~~ 108 | 109 | - 功能: 110 | 更新表table_name中满足条件的记录,使列col1的值为v1、列col2的值为v2、…、列coln的值为vn等。 111 | 112 | - 注意: 113 | 如不给出条件,则更新表中所有记录。 114 | 115 | - 例如 116 | account表中,账号为“1280316401“的账户取款200元后应更新余额,使用语句如下: 117 | 118 | ~~~sql 119 | UPDATE account SET accountAmount=accountAmount-200 120 | WHERE accountNumber =’1280316401’ 121 | ~~~ 122 | 123 | ##### 删除语句 124 | 125 | - 格式: 126 | 127 | ~~~sql 128 | DELETE FROM table_name 129 | [WHERE condition_expression] 130 | ~~~ 131 | 132 | - 功能: 133 | 删除表table_name中满足条件的记录。 134 | 135 | - 特别注意: 136 | 如果不给出条件,则删除表中所有记录。 137 | 138 | - 例如, 139 | 对account表中,账号为“1280316401“的账户进行销户处理,语句如下: 140 | 141 | ~~~sql 142 | DELETE FORM account WHERE accountNumber=’1280316401’ 143 | ~~~ 144 | 145 | 146 | 147 | ## JDBC概述 148 | 149 | - 类似于Microsoft的ODBC[^1]。 150 | - JDBC是Java DataBase Connectivity的缩写,它是一种可用于执行SQL语句的Java API,由一组用 Java编写的类和接口组成。 151 | [^1]: ODBC是OpenDatabaseConnectivity的英文简写。它是由Microsoft提出的为连接不同数据库而制定的一种接口标准,是用C语言实现的,标准应用程序数据接口。通过ODBC API,应用程序可以存取保存在多种不同数据库管理系统(DBMS)中的数据,而不论每个DBMS使用了何种数据存储格式和编程接口。几乎所有的数据库都支持这一标准。
ODBC有其不足之处,比如它并不容易使用,没有面向对象的特性等等。
ODBC的结构包括四个主要部分:应用程序接口、驱动器管理器、数据库驱动器和数据源。 152 | 153 | - Java程序使用JDBC与数据库进行通信,并用它操纵数据库中的数据。 154 | - JDBC主要提供了跨平台的数据库访问方法,为数据库应用开发人员提供了一种标准的应用程序设计接口,使- 开发人员可以用纯Java语言编写完整的数据库应用程序。 155 | - JDBC是一种规范,它让各数据库厂商为Java程序员提供标准的数据库访问类和接口,这样就使得独立于DBMS的Java应用程序的开发工具和产品成为可能。 156 | 157 | 1996年夏,Sun公司推出了Java数据库连接(Java Database Connectivity,JDBC)工具包的第一个版本。 158 | 159 | 160 | ## 使用JDBC访问数据库 161 | 162 | ### JDBC数据库驱动程序的功能是: 163 | 164 | - 一面用底层协议与数据库服务器进行对话; 165 | - 一面用JDBC API与用户程序进行对话。 166 | 167 | 为实现 “与平台无关”的特点,JDBC为我们提供了一个“驱动程序管理器”,它能动态维护数据库查询所需的所有驱动程序对象。 168 | 用户可以从数据库供应商那里获得JDBC数据库驱动程序。 169 | 170 | ![](fig/jdbc.png) 171 | 172 | Java应用程序 173 | Java程序包括应用程序、Applet和Servlet,这些类型的程序都可以利用JDBC方法完成对数据库的访问和操作。 174 | 175 | JDBC驱动程序管理器 176 | JDBC驱动程序管理器能够动态地管理和维护数据库查询所需要的所有厂商或第三方所提供的驱动程序对象,实现Java任务与特定驱动程序的连接,从而体现JDBC与平台无关这一特点。 177 | 178 | 驱动程序 179 | 这里的驱动程序一般由数据库厂商或第三方提供,它由JDBC方法调用,向特定数据库发送SQL请求,并为Java程序获取结果。 180 | 181 | 数据库 182 | 这里的数据库是指Java程序需要的数据库以及数据库管理系统。 183 | 184 | 185 | #### JDBC驱动程序类型 186 | JDBC驱动程序按照连接方式的不同可以分为四种类型: 187 | 188 | ##### JDBC-ODBC Bridge 189 | 将对JDBC的调用转化为ODBC的调用,要求本地机必须安装ODBC驱动程序,然后注册一个ODBC数据源名 。 190 | 191 | 使用JDBC-ODBC Bridge,JDBC调用最终转化为ODBC调用,应用程序可以通过选择适当的ODBC驱动程序来实现对多个厂商的数据库访问。 192 | 这种方式也存在局限性。 193 | JDBC-ODBC Bridge采用Native代码(C语言),因此,在使用时,所有的本地数据库都必须安装在一台计算机上,并被正确设置。 194 | 这种数据库连接有着相当的开销和复杂性,因为调用必须从JDBC到Bridge,再到ODBC,并再从ODBC到本地客户API,直到数据库。 195 | 这种驱动程序不容许Java Applet即时发送。 196 | ODBC不能解决的问题,JDBC-ODBC Bridge也不能解决,比如:Bridge不能通过Internet来访问数据库。 197 | 198 | ![](fig/jdbc2.png) 199 | 200 | ##### JDBC-Native API Bridge 201 | 直接将用户的调用转化为对数据库客户端API的调用,要求本地机必须安装好特定的驱动程序,显然限制了应用程序对其它数据库的使用。 202 | 203 | Native API Bridge驱动程序利用客户机上的本地代码库来与数据库进行直接通信。与JDBC-ODBC Bridge一样,这种驱动程序也存在着许多限制。由于它使用的是本地库,因此这些库就必须事先安装在客户机上。 204 | 205 | ![](fig/jdbc3.png) 206 | 207 | ##### JDBC-MiddleWare 208 | 它是独立于数据库服务器的,它和一个中间件服务器通讯,由中间件负责与数据库通讯。 209 | 210 | 这种类型的JDBC驱动程序是4中类型中最灵活的。这种驱动程序通常被用在三层网络解决方案中,并能够被发布到Internet上。这种类型的驱动程序是一种纯Java的驱动程序,它将JDBC调用转换为一种与DBMS独立的网络协议并与某种中间层连接,然后通过中间层,采用第一、第二或第四中驱动程序与数据库通信。这种驱动程序通常由一些与数据库产品无关的公司开发。 211 | 212 | ![](fig/jdbc4.png) 213 | 214 | ##### Pure JDBC Driver 215 | 使用该类型的应用程序无需安装附加的软件,所有对数据库的操作都直接由JDBC驱动程序完成。 216 | 217 | 这种JDBC驱动程序也是一种纯Java的驱动程序,它通过本地协议直接与数据库引擎相连。有了合适的通信协议,这种驱动程序也能够应用于Internet。该类驱动程序相对于其他类型的驱动程序的优势在于它的性能,在它与数据库引擎和客户机之间没有本地代码层或中间层软件。 218 | 219 | ![](fig/jdbc5.png) 220 | 221 | 222 | ### JDBC API 223 | 224 | 简单地说,JDBC主要完成下列三项任务:  225 | 226 | - 同一个数据库建立连接; 227 | - 向数据库发送SQL语句; 228 | - 处理数据库返回的结果。 229 | 230 | 这些任务由JDBC API来完成。JDBC API 被描述成为一组抽象的Java接口。 231 | 这些接口都可能产生异常,如:ClassNotFoundException、SQLException异常,因而编写程序时必须对抛出的异常进行捕获。 232 | 233 | ![](fig/jdbcapi.png) 234 | 235 | #### 主要接口 236 | 237 | (1) 驱动程序管理器DrvierManager 238 | 用来加载驱动程序,管理应用程序和已注册的驱动程序的连接。 239 | 240 | (2) 连接Connection 241 | 封装了应用程序与数据库之间的连接信息。 242 | 243 | (3) 驱动程序Driver 244 | 负责定位并访问数据库,建立数据库连接和处理所有与数据库的通讯。 245 | 246 | (4) 语句Statement 247 | 用来在数据库中执行一条SQL语句。 248 | 249 | (5) 结果集ResultSet 250 | 负责保存执行查询后返回的数据。 251 | 252 | ### 编写JDBC程序一般步骤 253 | 254 | import java.sql.*; 255 | 256 | (1)加载驱动程序: 257 | 258 | ~~~java 259 | Class.forName(driverClass); 260 | ~~~ 261 | 262 | DriverManager 类是 JDBC 的管理层,作用于用户程序和驱动程序之间。它跟踪可用的驱动程序,并在数据库和相应驱动程序之间建立连接。负责管理JDBC驱动程序。使用JDBC驱动程序之前,必须先将驱动程序加载并向DriverManager注册后才可以使用,同时提供方法来建立与数据库的连接。 263 | 加载 Driver 类,并且实现自动在 DriverManager 中注册,这一过程通常通过调用方法 Class.forName()来完成,这将显式地加载驱动程序类。 264 | 265 | 266 | 为了要连接数据库,您必须要有相应数据库的JDBC驱动程序,并将驱动程序的.jar文件加入到Classpath的设置中。 267 | DriverManager类管理各种数据库驱动程序,建立新的数据库连接,以便Java应用程序能够使用正确的JDBC驱动程序。 268 | 加载Driver类,然后自动在DriverManager中注册的方式有两种: 269 | 1) 通过调用方法Class.forName()。这种方法将显式地加载驱动程序类。 270 | 2) 通过将驱动程序添加到java.lang.System 的属性jdbc.drivers 中。 271 | 注意:加载驱动程序的第二种方法需要持久的预设环境。如果对这一点不能保证,则调用方法Class.forName 显式地加载每个驱动程序就显得更为安全。 272 | 273 | 274 | 275 | ~~~java 276 | Statement to load a driver: 277 | Class.forName("JDBCDriverClass"); 278 | 279 | A driver(实现了java.sql.Driver接口的类) is a class. For example: 280 | 281 | Database Driver Class Source 282 | Access sun.jdbc.odbc.JdbcOdbcDriver Already in JDK 283 | MySQL com.mysql.jdbc.Driver Website 284 | Oracle oracle.jdbc.driver.OracleDriver Website 285 | 286 | The JDBC-ODBC driver for Access is bundled in JDK. 287 | MySQL driver class is in mysqljdbc.jar 288 | Oracle driver class is in classes12.jar 289 | 290 | To use the MySQL and Oracle drivers, you have to add mysqljdbc.jar and classes12.jar in the classpath using the following DOS command on Windows: 291 | classpath=%classpath%;c:\book\mysqljdbc.jar;c:\book\classes12.jar 292 | 293 | Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); 294 | //加载驱动程序,这里是一个JDBC-ODBC桥,类型一 295 | Connection con = DriverManager.getConnection("jdbc:odbc:userlist", "user", ""); 296 | // 表示是通过ODBC来连接数据库的,userlist为ODBC数据源名, user为此数据源的用户ID 297 | //建立一个连接 298 | 299 | ~~~ 300 | 301 | (2)建立与数据库的连接: 302 | 303 | ~~~java 304 | Connection con = DriverManager.getConnection(url); 305 | ~~~ 306 | 307 | 使用DriverManager类中的静态方法 308 | 309 | ~~~java 310 | Connection con= getConnection(databaseURL) 311 | ~~~ 312 | 313 | Connection实际上是一个接口,它负责维护Java应用程序与数据库之间的连接。 314 | Connection 对象代表与数据库的连接。连接过程包括所执行的 SQL 语句和在该连接上所返回的结果。一个应用程序可与单个数据库有一个或多个连接,或者可与许多数据库有连接。 315 | 316 | |Database| URL Pattern| 317 | |:---|:---| 318 | |Access | jdbc:odbc:dataSource| 319 | |MySQL | jdbc:mysql://hostname/dbname | 320 | |Oracle | jdbc:oracle:thin:@hostname:port#:oracleDBSID| 321 | 322 | For Access: 323 | 324 | >Connection connection = DriverManager.getConnection("jdbc:odbc:ExampleMDBDataSource"); 325 | 326 | For MySQL: 327 | 328 | >Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/test"); 329 |   330 | For Oracle: 331 | 332 | >Connection connection = DriverManager.getConnection 333 | ("jdbc:oracle:thin:@liang.armstrong.edu:1521:orcl", "scott", "tiger"); 334 | 335 | 336 | 与数据库建立连接的标准方法是调用方法: 337 | 338 | ~~~java 339 | DriverManger.getConnection(String url) 340 | DriverManger.getConnection(String url, Properties info) 341 | DriverManger.getConnection(String url, String user, String password) 342 | ~~~ 343 | 344 | JDBC中URL字符串的准确形式随着数据库的不同而有所变化,其一般形式是: 345 | 346 | ~~~java 347 | jdbc:: 348 | ~~~ 349 | 350 | 351 | 352 | (3)创建Statement对象: 353 | 354 | ~~~java 355 | Statement stmt = con.createStatement(); 356 | ~~~ 357 | 358 | >Statement statement = connection.createStatement(); 359 | 360 | Statement 对象用于将 SQL 语句发送到数据库中,并返回结果。 361 | 362 | 方 法 : ResultSet executeQuery(String sql) 363 | 说 明 : 执行SQL查询指令select并返回结果集 364 | 365 | 方 法 : int executeUpdate(String sql) 366 | 说 明 : 执行对数据库修改的SQL指令如insert、delete、update等 367 | 368 | 方 法 :void close() 369 | 说 明 :断开对数据库的连接 370 | 371 | (1) 创建 Statement 对象 372 | Statement stmt = con.createStatement(); 373 | 374 | (2) 使用 Statement 对象执行语句 375 | String sql = "select * from userlist where username='" + username + "'"; 376 | ResultSet rs = stmt.executeQuery(sql); 377 | 378 | (3) 语句完成 379 | 语句在已执行且所有结果返回时,即认为已完成。对于返回一个结果集的 executeQuery 方法,在检索完 ResultSet 对象的所有行时该语句完成。对于方法 executeUpdate,当它执行时语句即完成。 380 | 381 | Connection con =DriverManager.getConnection(url); 382 |  Statement statement = connection.createStatement(); //创建Statement对象 383 | 384 | statement.executeUpdate 385 | ("create table Temp (col1 char(5), col2 char(5))"); 386 | 387 | ResultSet resultSet = statement.executeQuery 388 | ("select firstName, mi, lastName from Student where lastName = 'Smith'"); 389 | 390 | 执行SQL语句 391 | 连接一旦建立,就可用来向它所涉及的数据库传送SQL语句。 392 | JDBC提供了三个类,用于向数据库发送SQL语句。Connection接口中的三个方法可用于创建这些类的实例。 393 | (1) Statement,由方法createStatement所创建。Statement 对象用于发送简单的SQL语句。 394 | (2) PreparedStatement,由方法prepareStatement所创建。PreparedStatement对象用于发送带有一个或多个输入参数的SQL语句。 395 | (3) CallableStatement,由方法prepareCall所创建。CallableStatement对象用于执行SQL存储程序——一组可通过名称来调用(就像函数的调用那样)的SQL语句。 396 | 397 | 398 | 399 | (4)得到查询结果集或者执行UPDATE等操作: 400 | 401 | ~~~java 402 | ResultSet rs = stmt.executeQuery(quaryStatement); 403 | ~~~ 404 | 405 | 检索结果 406 | 407 | SQL语句发送以后,返回的结果通常存放在一个ResultSet类的对象中,ResultSet对象可以看作是一个表,这个表中包含由SQL返回的列名和相应的值,ResultSet对象中维持了一个指向当前行的指针,通过一系列的getXXX方法,可以检索当前行的各个列,并显示出来。 408 | 409 | 410 | (5)对结果集(Resultset)提取执行结果: 411 | 使用next()方法,依次访问ResultSet对象中包含的检索结果行。或者使用getXXX方法从当前行指定列中提取不同类型的数据。 412 | 413 | ResultSet结果集一般是一个表,该表的当前行可以访问,当前行的初始位置是null,使用next()能够移动到下一行,可以使用各种getXXX 方法从当前行检索值。 414 | 415 | ~~~java 416 | ResultSet rs = stmt.executeQuery(sql); 417 | //列印结果集 418 | while(rs.next()) 419 | { 420 | String ps = rs.getString("password"); 421 | if (ps.equals(password)) { 422 | //验证通过 423 | ok=true; 424 | } 425 | } 426 | ~~~ 427 | 428 | 429 | (6)关闭数据库连接: 430 | 431 | 在对象使用完毕后,应当使用close( )方法解除与数据库的连接,并关闭数据库。 432 | 433 | ~~~java 434 | con.close(); 435 | ~~~ 436 | 437 | ## 使用JDBC访问数据库的示例 438 | 439 | ~~~java 440 | import java.sql.*; 441 | public class SimpleJdbc { 442 | public static void main(String[] args) 443 | throws SQLException, ClassNotFoundException { 444 | // Load the JDBC driver 445 | Class.forName("com.mysql.jdbc.Driver"); 446 | System.out.println("Driver loaded"); 447 |   448 | // Establish a connection 449 | Connection connection = DriverManager.getConnection 450 | ("jdbc:mysql://localhost/test"); 451 | System.out.println("Database connected"); 452 |   453 | // Create a statement 454 | Statement statement = connection.createStatement(); 455 |   456 | // Execute a statement 457 | ResultSet resultSet = statement.executeQuery 458 | ("select firstName, mi, lastName from Student where lastName " 459 | + " = 'Smith'"); 460 |   461 | // Iterate through the result and print the student names 462 | while (resultSet.next()) 463 | System.out.println(resultSet.getString(1) + "\t" + 464 | resultSet.getString(2) + "\t" + resultSet.getString(3)); 465 |   466 | // Close the connection 467 | connection.close(); 468 | } 469 | } 470 | 471 | ~~~ 472 | 473 | ## 练习 474 | 475 | 1.试述JDBC驱动程序有哪几种。 476 | 2.SQL语言包括哪几种基本语句来完成数据库的基本操作? 477 | 3.JDBC的作用是什么?主要完成什么任务? 478 | 4.怎样加载JDBC驱动程序类?举例说明。 479 | 5.Statement接口的作用是什么? 480 | 6.executeQuery()方法的作用是什么? 481 | 7.简述编写JDBC程序的一般步骤。 482 | 483 | --- 484 | 485 | 本文档 Github : 486 | https://github.com/bushehui/Java_tutorial 487 | 488 | 489 | 490 | 491 | 494 | 495 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | -------------------------------------------------------------------------------- /fig/CDevPro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/CDevPro.png -------------------------------------------------------------------------------- /fig/DBMS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/DBMS.png -------------------------------------------------------------------------------- /fig/DBMS2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/DBMS2.png -------------------------------------------------------------------------------- /fig/ErrException.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/ErrException.png -------------------------------------------------------------------------------- /fig/ErrException2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/ErrException2.png -------------------------------------------------------------------------------- /fig/Error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Error.png -------------------------------------------------------------------------------- /fig/ExceptionLayers.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/ExceptionLayers.jpg -------------------------------------------------------------------------------- /fig/JDBC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/JDBC.png -------------------------------------------------------------------------------- /fig/JDBC2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/JDBC2.png -------------------------------------------------------------------------------- /fig/JDBC3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/JDBC3.png -------------------------------------------------------------------------------- /fig/JDBC4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/JDBC4.png -------------------------------------------------------------------------------- /fig/JDBC5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/JDBC5.png -------------------------------------------------------------------------------- /fig/JDBCAPI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/JDBCAPI.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-4e4e2e7eaf3edea9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-4e4e2e7eaf3edea9.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-4f8abdf9fa7ef630.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-4f8abdf9fa7ef630.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-5989238d90b80c55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-5989238d90b80c55.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-5aed0e7d50180e47.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-5aed0e7d50180e47.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-74dc7e59ddffda64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-74dc7e59ddffda64.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-764c12e8c74ab0dd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-764c12e8c74ab0dd.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-7c2effe451a1bb9d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-7c2effe451a1bb9d.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-7e4a2b32bca3882e.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-7e4a2b32bca3882e.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-8ed65d3657480ed0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-8ed65d3657480ed0.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-9120c6b8755abbcc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-9120c6b8755abbcc.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-9ac51deef1e7516d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-9ac51deef1e7516d.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-a0d0a03f1a1e1680.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-a0d0a03f1a1e1680.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-a18a40fd0180afaa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-a18a40fd0180afaa.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-af9d74c2bfee9385.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-af9d74c2bfee9385.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-b03fb6e32e6d7ebb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-b03fb6e32e6d7ebb.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-bdb51e206ee9ca0d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-bdb51e206ee9ca0d.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-be47d789929ec252.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-be47d789929ec252.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-d0d8cda0cc9ca07c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-d0d8cda0cc9ca07c.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-d105e32dea0dc8f9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-d105e32dea0dc8f9.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-d753ccedc0c8af92.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-d753ccedc0c8af92.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-d800586dfc967291.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-d800586dfc967291.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-e63eb183f6f860cf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-e63eb183f6f860cf.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-e8a41a869911f730.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-e8a41a869911f730.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-ee23f25321b04d79.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-ee23f25321b04d79.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-f506cbdca8593918.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-f506cbdca8593918.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-f6fefc4f54458850.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-f6fefc4f54458850.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-f8b7cdd3e8abf3e8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-f8b7cdd3e8abf3e8.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-fe108c58f2fee95f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-fe108c58f2fee95f.png -------------------------------------------------------------------------------- /fig/Java-Mindmap/4120002-febc1570c2425cf0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java-Mindmap/4120002-febc1570c2425cf0.png -------------------------------------------------------------------------------- /fig/Java.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Java.png -------------------------------------------------------------------------------- /fig/JavaDataType.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/JavaDataType.png -------------------------------------------------------------------------------- /fig/JavaDevPro.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/JavaDevPro.png -------------------------------------------------------------------------------- /fig/JavaRun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/JavaRun.png -------------------------------------------------------------------------------- /fig/Javac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/Javac.png -------------------------------------------------------------------------------- /fig/JvmSpec7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/JvmSpec7.png -------------------------------------------------------------------------------- /fig/LearningJAVA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/LearningJAVA.png -------------------------------------------------------------------------------- /fig/SearchExample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/SearchExample.png -------------------------------------------------------------------------------- /fig/classBufferStream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classBufferStream.png -------------------------------------------------------------------------------- /fig/classBufferStreamChain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classBufferStreamChain.png -------------------------------------------------------------------------------- /fig/classError.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classError.png -------------------------------------------------------------------------------- /fig/classFilter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classFilter.png -------------------------------------------------------------------------------- /fig/classInput.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classInput.png -------------------------------------------------------------------------------- /fig/classInputChain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classInputChain.png -------------------------------------------------------------------------------- /fig/classNumber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classNumber.png -------------------------------------------------------------------------------- /fig/classOutput.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classOutput.png -------------------------------------------------------------------------------- /fig/classOutputChain.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classOutputChain.png -------------------------------------------------------------------------------- /fig/classReader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classReader.png -------------------------------------------------------------------------------- /fig/classWriter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classWriter.png -------------------------------------------------------------------------------- /fig/classright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/classright.png -------------------------------------------------------------------------------- /fig/fileio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/fileio.png -------------------------------------------------------------------------------- /fig/flowsample1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/flowsample1.png -------------------------------------------------------------------------------- /fig/flowsample2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/flowsample2.png -------------------------------------------------------------------------------- /fig/flowsample3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/flowsample3.png -------------------------------------------------------------------------------- /fig/indonesian_map.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/indonesian_map.jpg -------------------------------------------------------------------------------- /fig/iolevel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/iolevel.png -------------------------------------------------------------------------------- /fig/iostream.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/iostream.png -------------------------------------------------------------------------------- /fig/iostreaminput.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/iostreaminput.png -------------------------------------------------------------------------------- /fig/iostreamoutput.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/iostreamoutput.png -------------------------------------------------------------------------------- /fig/james_gosling_java.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/james_gosling_java.jpg -------------------------------------------------------------------------------- /fig/java2JDK.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/java2JDK.gif -------------------------------------------------------------------------------- /fig/object-class.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/object-class.jpg -------------------------------------------------------------------------------- /fig/operator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/operator.png -------------------------------------------------------------------------------- /fig/packagedir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/packagedir.png -------------------------------------------------------------------------------- /fig/sortsample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/sortsample.png -------------------------------------------------------------------------------- /fig/sortsample2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/sortsample2.png -------------------------------------------------------------------------------- /fig/swing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/swing.png -------------------------------------------------------------------------------- /fig/swing2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/swing2.png -------------------------------------------------------------------------------- /fig/swing3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/swing3.png -------------------------------------------------------------------------------- /fig/swing4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/swing4.png -------------------------------------------------------------------------------- /fig/swingevents.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/swingevents.png -------------------------------------------------------------------------------- /fig/swingevents2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/swingevents2.png -------------------------------------------------------------------------------- /fig/swingjframe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/swingjframe.png -------------------------------------------------------------------------------- /fig/swingjframe2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/swingjframe2.png -------------------------------------------------------------------------------- /fig/swingmvc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/swingmvc.png -------------------------------------------------------------------------------- /fig/thread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/thread.png -------------------------------------------------------------------------------- /fig/thread2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/thread2.png -------------------------------------------------------------------------------- /fig/thread3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bushehui/Java_tutorial/47db33fbbf26ea975fc76b053bd3ead3bc6dac56/fig/thread3.png --------------------------------------------------------------------------------