Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

TIEP111 Ohjelmointi 2

Tämä on Jyväskylän yliopiston järjestämän TIEP111 Ohjelmointi 2 -opintojakson oppimateriaali.

Tietoja opintojaksosta

Opintojaksolla opit

  • oliopohjaisen ohjelmoinnin perusteita ja periaatteita
  • tuottamaan pieniä ja keskisuuria ohjelmia
  • ohjelmistosuunnittelun periaatteita
  • ohjelman automaattista testaamista
  • graafisen käyttöliittymän suunnittelua ja kehittämistä
  • erilaisia ohjelmoijan työkaluja ja tekniikoita
    • ml. rekursio, geneeriset tyypit, funktionaalinen ohjelmointi

Tarkemmat tiedot löydät opintojakson Sisu-esitteestä.

Esitiedot

Ohjelmoinnin perustiedot, kuten Ohjelmointi 1 tai vastaavat tiedot

Tässä muutama pikavinkki tässä materiaalissa navigoimiseen.

  • Sisällysluettelon saat auki ja kiinni sivupalkki-kuvakkeesta .
  • Voit selata materiaalia eteen- ja taaksepäin nuolikuvakkeista sivun vasemmassa ja oikeassa laidassa (tai ihan sivun alalaidassa, jos käytät mobiililaitetta) .
  • Hakutoiminnon saat auki suurennuslasista oikeasta yläreunasta tai painamalla S-kirjainta näppäimistöltä .

huomautus

Teemme kokonaisvaltaisen uudistuksen oppimateriaaliin sekä tehtäviin kevään 2026 aikana. Osa materiaalista julkaistaan kurssin edetessä. Uudistamisesta johtuen sisällössä voi olla myös keskeneräisyyksiä ja virheitä. Pahoittelemme tästä mahdollisesti aiheutuvaa haittaa. Pyydämme, että ilmoitat virheistä tai parannusehdotuksista GitHubin kautta (katso alla) tai suoraan opettajien sähköpostiin opet@TODO.

Haluatko parannella tätä materiaalia?

Jos löydät materiaalista virheitä, voit ehdottaa korjauksia tai parannuksia klikkaamalla sivun alareunasta. Ehdotuksen tekemiseksi tarvitset GitHub-tilin.

Tekijät ja lisenssi

Ohjelmointi 2 oppimateriaali © 2025 by Denis Zhidkikh, Sami Sarsa, Antti-Jussi Lakanen, Rauli Ruokokoski, Karri Sormunen.

Kiitos Jonne Itkoselle palautteesta ja parannusehdotuksista.

Materiaali on julkaistu CC-BY-SA-4.0-lisenssillä. Tarkemmat tiedot löydät materiaalin GitHub-sivulta.

Suorittaminen

Voit valita kolmesta suoritustavasta itsellesi sopivimman. Kaikki suoritustavat sisältävät harjoitustyön tekemisen.

Suoritustapojen yksityiskohdat eroavat aikaisemmista toteutuksista jonkin verran, joten jos olet aiemmin yrittänyt suorittaa kurssia, lue tämä osio huolellisesti läpi.

Suoritustapa 1

Tentti, harjoitustehtävät, harjoitustyö aikataulussa

Suoritus koostuu seuraavista osasuorituksista (kaikista on saatava hyväksytty):

  1. Keräät jokaisesta osasta vähintään 50% siitä pistemäärästä mitä harjoitustehtävien perustehtävistä voi saada1
  2. Teet harjoitustyön aikataulussa
  3. Teet tentin hyväksytysti

1 Harjoitustehtävät muodostuvat perustehtävistä ja lisätehtävistä. "100%" tarkoittaa tässä yhteydessä sitä pistemäärää, mitä perustehtävistä voi saada. Voit kuitenkin tehdä myös lisätehtäviä kartuttaaksesi prosenttiosuuttasi ja siten tehdä jopa >= 100% pisteistä.

Arvosana muodostuu harjoitustehtävien ja tentin painotettuna keskiarvona (40/60). Tarkempi kuvaus on alla.

Harjoitustehtävien pisterajat:

Kerättyjä pisteitä enintäänHarjoitustehtävien arvosana
<50%0
50%1
60%2
70%3
80%4
>=90%5

Ensimmäisen kuuden osan kohdalla on mahdollista saada myös ns. DL-BONUS-pisteitä: Jos teet osasta vähintään 50%2 osan takarajaan mennessä, lisätään kyseisen osan harjoitustehtävien pistemäärään 0,5 pistettä. Niinpä DL-BONUS-pisteitä voi saada maksimissaan 6 * 0,5 = 3 pistettä. Karkeasti ottaen, kun teet yhden osan takarajaan mennessä, se vaikuttaa noin 1%-yksikön verran kokonaisprosenttiisi.

2 Edelleen, "50%" tarkoittaa tässä yhteydessä puolet siitä pistemäärästä, mitä kyseisen osan perustehtävistä voi saada.

Näet etenemissivulla kerättyjen tehtäväpisteidän määrän ja prosenttiosuuden sekä DL-BONUS-pisteet erikseen. (Linkki TODO!)

Lopullinen arvosana muodostuu harjoitustehtävien arvosanan ja tentin arvosanan painotettuna keskiarvona. Harjoitustehtävistä saatua arvosanaa painotetaan 40% ja tentistä saatua arvosanaa painotetaan 60%. Sekä harjoitustehtävistä että tentistä täytyy saada vähintään arvosana 1, jotta kurssista voi saada hyväksytyn arvosanan.

Esim1Esim2Esim3
Osuus harjoitustehtävistä (sis DL-BONUS)70%90%70%
Harjoitustehtävien arvosana353
Tentin arvosana145
Painotettu keskiarvo1.84.44.6
Pyöristetty arvosana245

Harjoitustehtävistä saatu arvosana otetaan lukuun kolmeen ensimmäiseen tenttiin, jotka opiskelija suorittaa, ja enintään yhden vuoden sisällä opintojakson viimeisestä suorituspäivästä.

Suoritustapa 2

105% harjoitustehtävistä, suullinen kuulustelu harjoitustyöstä, harjoitustyö aikataulussa

  1. Keräät vähintään 100% pistettä harjoitustehtävistä (kaikista osista yhteensä) JA keräät kaikki DL-BONUS-pisteet (6 * 0.5 = 3 pistettä)
  2. Teet harjoitustyön aikataulussa
  3. Osallistut suulliseen kuulusteluun, jossa ohjaaja arvioi harjoitustyösi

Arvosanasi on tällöin 1, jota voit vapaaehtoisesti korottaa tentillä.

Suoritustapa 3

Harjoitustyö ja loppukoe.

  1. Teet harjoitustyön
  2. Teet tasokokeen tapaisen loppukokeen (tämä on eri asia kuin tentti)

Arvosana muodostuu loppukokeen arvosanasta.

Työkaluohjeet

Ohjelmointi 2 -opintojaksolla käytämme seuraavia työkaluja:

  • Java Development Kit (JDK) - ohjelmistokehityspaketti, joka sisältää muun muassa Java-kääntäjän sekä virtuaalikoneen Java-ohjelmien ajamista varten.

  • Git - versiohallintaohjelma (engl. Version Control Software, VCS), joka mahdollistaa koodin versioinnin ja yhteistyön koodaajien välillä.

  • IntelliJ IDEA - integroitu kehitysympäristö (engl. Integrated Development Environment, IDE), jolla voi kehittää ja debugata muun muassa Java-ohjelmia. (koodin muokkaus, kääntäminen, ajaminen, virheenjäljitys). Käytämme IntelliJ IDEAn ilmaista Community Edition -versiota.

  • ComTest - työkalu dokumentaatiotestien kirjoittamiselle ja ajamiselle.

Yllä olevat ohjelmat löytyvät valmiiksi asennettuna Agoran mikroluokissa (Alban puoleinen pääty, 1. ja 2. kerros). Jos sinulla on oma tietokone, suosittelemme, että asennat ohjelmat myös siihen. Erityisesti harjoitustyön tekeminen on helpompaa, kun kaikki tarvittavat ohjelmat on myös omalla tietokoneella.

tärkeää

Tämän sivun ohjeet vaativat komentorivin käyttöä. Voit tarvittaessa kerrata komentorivin perusteita seuraavista linkeistä:

Kurssilla virallisesti tuettuja käyttöjärjestelmiä ovat Windows, macOS ja Linux. Työkalujen asentaminen ChromeOS:ään saattaa olla mahdollista, mutta emme valitettavasti voi tarjota tukea kyseiseen käyttöjärjestelmään. Tästä syystä emme suosittele ChromeOS:n käyttöä.

Valitse käyttöjärjestelmäsi alta:

Valitse käyttöjärjestelmäsi yllä olevista vaihtoehdoista.

Esivalmistelut

Valitse käyttöjärjestelmäsi yllä olevista vaihtoehdoista.

Git

Valitse käyttöjärjestelmäsi yllä olevista vaihtoehdoista.

IntelliJ IDEA

Valitse käyttöjärjestelmäsi yllä olevista vaihtoehdoista.

Java Development Kit (JDK)

  1. Avaa IntelliJ IDEA ja odota, kunnes pääset Welcome to IntelliJ IDEA -näkymään.

  2. Klikkaa ikkunan keskellä tai ylädassa olevaa New Project -painiketta:

  3. Avautuneesta ikkunasta klikkaa JDK-alasvetolaatikkoa ja valitse Download JDK... -painike:

  4. Aseta avautuneessa ikkunassa asetukset seuraavasti:

    • Version: 25
    • Vendor: Oracle OpenJDK Älä muuta Location-kohdassa olevaa polkua!

    Paina lopuksi Select-painiketta.

  5. Jätä muut projektin asetukset sellaiseksi kuin ne ovat. Paina oikeassa alalaidassa olevaa Create-painiketta ja anna projektin latautua.

    Tämä avaa IntelliJ IDEA -kehitysympäristön käyttöliittymän.

    JDK:n lataamisessa voi mennä aikaa. Odota rauhassa, kunnes kaikki virheet ja punaiset tekstit häviää.

  6. Kun projekti on latautunut eikä virheitä näy, kokeile ajaa projekti painamalla oikeassa ylälaidassa olevaa Play-painiketta:

  7. Odota, kunnes ohjelma kääntyy. Jos kaikki toimii, ikkunan alapuolelle pitäisi ilmestyä konsoli-ikkuna, jossa näet seuraavan tekstin:

    Hello and welcome!
    i = 1
    i = 2
    i = 3
    i = 4
    i = 5
    
  8. Voit nyt sulkea IntelliJ IDEA:n.

ComTest

  1. Avaa IntelliJ IDEA ja odota, kunnes pääset Welcome to IntelliJ IDEA -näkymään.

    Jos sinulle avautui jokin vanha projekti, klikkaa yläpalkista tai hampurilaisvalikosta File > Close project. Tämä vie sinut takaisin Welcome to IntelliJ IDEA -näkymään.

  2. Klikkaa ikkunan vasemmassa alalaidassa oleva Configure (Ratas-ikoni) > Settings.

  3. Valitse vasemmalla puolella olevista asetusnäkymistä Plugins

  4. Valitse Marketplace-välilehti ja hae hakusanalla ComTest

  5. Valitse Comtest Runner -pluginin kohdalta Install

  6. Paina Save

  7. Sulje IntelliJ IDEA

Mitä seuraavaksi?

Onneksi olkoon! Sinulla on seuraavaksi kaikki tarvittavat kurssityökalut. Voit jatkaa tästä varsinaisiin materiaaleihin.

Tuki ja palaute

Kevään 2026 ohjauskauden (10.1.-30.4.) aikana on tarjolla seuraavat tukikanavat:

TukikanavaAikaPaikka/Linkki
Lähiohjauske 10-16, to 10-16, pe 10-16Agoralla luokat Ag B213.1 Lakes ja Ag B212.2 Mountains
Etäohjauske 10-16, to 8-18, pe 10-16Ohjelmointi 2 Teams-kanava
Vastuuopettajien ja tuntiopettajien sähköpostiosoiteJatkuvaohj2-opet@tim.jyu.fi

Ohjaukset ovat yhteisiä ITKP102 Ohjelmointi 1- ja ITKA2004 Tietokannat ja tiedonhallinta -opintojaksojen kanssa. Ohjaajat auttavat kummankin kurssin opiskelijoita.

Ohjausaikoja saatetaan lisätä tai poistaa kysynnän mukaan; kerro aikatoiveistasi opettajille sähköpostitse.

Haluatko Sisun kalenteriin ohjausaikoja näkyviin? (Avaa ohje klikkaamalla)
  1. Kirjaudu Sisuun

  2. Jos olet jo ilmoittautunut kurssille, klikkaa ylhäällä välilehteä Opintokalenteri tai klikkaa sitä hampurilaisvalikosta

  3. Selaa oikealla oikea kurssi näkyville, eli tässä tapauksessa Ohjelmointi 2

  4. Klikkaa oikealla olevaa oikealle osoittavaa väkästä Ohjelmointi 2 -kurssin kohdalla

  5. Skrollaa alaspäin, kunnes tulee alaotsikko Pääteohjaus

  6. Jos ei vielä näy, niin skrollaa alaspäin, kunnes näkyy Muiden ryhmien tiedot ja klikkaa sitä

  7. Nyt voit skrollaamalla alaspäin haluamiesi pääteohjauksien kohdalta klikata nappulaa Näytä tapahtumat kalenterissa.

    Image

  8. Nyt kyseisen ryhmän ohjausajat näkyvät sinulla automaattisesti. Tarvittaessa voit poistaa ryhmän tapahtumia viikkokohtaisesti Tapahtumakalenterista.

Ohjeet Teams-ohjauksiin liittymiseksi (tutkinto-opiskelijat)

  1. Kirjaudu yliopiston tunnuksellasi Microsoft Teamsiin osoitteessa https://teams.microsoft.com. Käyttäjätunnus on muotoa käyttäjätunnus@jyu.fi (esim. mameikal@jyu.fi). Tunnuksen muoto student.jyu.fi ei käy. Tunnuksen toimiminen vaatii, että olet hyväksynyt Office 365 -palvelut OMA-palvelussa (https://sso.jyu.fi).

  2. Lataa Teams-sovellus (suositus) tai käytä nettiversiota. Saatavilla on myös mobiilisovellus. Jos selaimella liittymisessä on ongelmia, tarkista ensin tukeeko Microsoft sitä täältä.

  3. Teams-sovelluksessa klikkaa TeamsJoin or create teamJoin a team with a code

  4. Syötä koodi nnobn49

  5. Testaa kaverin kanssa, että puhelu ja ruudun jakaminen toimii. Sinun tulee tarvittaessa sallia oikeudet käyttöjärjestelmäsi asetuksista.

Ohjeet Teams-ohjauksiin liittymiseksi (avoin yliopisto, erilliset opinto-oikeudet)

Lähetä sähköpostilla alla oleva pyyntö osoitteeseen ohj2-opet@tim.jyu.fi.

Hei,

opiskelen Ohjelmointi 2 -kurssilla ei-tutkintoon johtavassa koulutuksessa.
Pyydän liittämään minut opintojakson Teams-ryhmään vieraana. 
Teamsissa käyttämäni sähköpostiosoite on: [oma sähköposti tähän].

Terveisin, [oma nimi]

Liitämme sinut viimeistään seuraavana arkipäivänä.

Etäohjauksiin osallistuminen ilman Teamsia

Jos et millään onnistu kirjautumaan Teamsiin tai et halua olla Teams-kanavalla, voit pyytää etäohjausta Zoomin kautta seuraavasti:

  1. Asenna Zoom sovellus koneellesi osoitteesta https://zoom.us/download (muut kuin tutkinto-opiskelijat) tai https://jyufi.zoom.us (tutkinto-opiskelijat; Valitse Download Client ihan alhaalta)
  2. Kirjaudu Zoomiin valitsemallasi tilillä, esim. Google-kirjautumista käyttäen (muut kuin tutkinto-opiskelijat) tai Single Sign-on / SSO -toiminnolla (tutkinto-opiskelijat; käytä company domainia jyufi)
  3. Aloita kokous New meeting toiminnolla
  4. Testaa Audio → Test speaker & mikrofone toiminnolla että äänet pelittää
  5. Ota kokouslinkki talteen Participants → Copy invite link
  6. Avaa ohjauspyyntölomake: https://forms.gle/5QULUPBHjjqS4ndf6
  7. Täytä omat tietosi ja HUOM Pasteta lisätietokenttään kohdassa 5 kopioimasi linkki
  8. Odota, että ohjaaja tulee huoneeseesi. Saatat joutua hyväksymään hänen sisäänpääsyn (riippuu kokoushuoneesi asetuksista)

Palaute ja kehittäminen

Olemme erittäin kiitollisia kaikesta palautteesta, joka auttaa meitä kehittämään opintojaksoa edelleen! Voit antaa palautetta ja kehitysehdotuksia opintojaksosta kolmella tavalla:

  1. Keräämme jatkuvaa palautetta opintojakson aikana. Nyt, kun olemme kehittämässä opintojakson sisältöjä ja toteutusta, tämä jatkuva palaute on erityisen tärkeää. Voit antaa palautetta anonyymisti alla olevan linkin kautta: TODO: Norppa-linkki tähän.

  2. Mikäli havaitset materiaalissa virheen, epäselvyyden, tai muun ongelman, voit raportoida siitä GitHubissa klikkaamalla kunkin sivun alareunassa olevia linkkejä. Voit myös ilmoittaa puutteista suoraan opettajille sähköpostitse osoitteeseen ohj2-opet@tim.jyu.fi.

  3. Opintojakson lopuksi jokainen Sisussa (tai Ilpo-portaalissa) ilmoittautunut saa henkilökohtaisen linkin kurssipalautekyselyyn, jossa voit antaa anonyymisti palautetta koko opintojaksosta.

Harjoitustyö

Harjoitustyöhön liittyvät tiedot julkaistaan erikseen opintojakson aikana.

Tentti

Lukuvuonna 2025-2026 tenttejä järjestetään seuraavasti

TenttiPäivämääräAikaPaikkaIlmoittautumislinkki
Kevät 1pp.kk.2025klo xx-xxAgora / ZoomIlmoittaudu
Kevät 2pp.kk.2025klo xx-xxAgora / ZoomIlmoittaudu
Kevät 3pp.kk.2025klo xx-xxAgora / ZoomIlmoittaudu
Kesä 1pp.kk.2025klo xx-xxAgora / ZoomIlmoittaudu
Kesä 2pp.kk.2025klo xx-xxAgora / ZoomIlmoittaudu
Syksy 1pp.kk.2025klo xx-xxAgora / ZoomIlmoittaudu
Syksy 2pp.kk.2025klo xx-xxAgora / ZoomIlmoittaudu
Syksy 3pp.kk.2025klo xx-xxAgora / ZoomIlmoittaudu

Voit osallistua tenttiin joko Agoran luentosalissa tai etänä Zoomin kautta.

Tenttiin tulee ilmoittautua viimeistään 72 tuntia ennen tentin alkuhetkeä. Ilmoittautumisen yhteydessä opiskelijan tulee hyväksyä sekä tentin säännöt (kuvattu alla). Ilmoittautumisen yhteydessä opiskelija valitsee myös tentin suoritustavan (salitentti tai etätentti).

Opiskelijan on todistettava henkilöllisyytensä ennen tentistä poistumista. Henkilöllisyyden todistamiseksi hyväksytään passi, henkilökortti tai ajokortti. Vain tunnistettujen opiskelijoiden suorituksen arvostellaan.

Tenttiaika on 4 tuntia. Ilmoita ilmoittautumisen yhteydessä, mikäli sinulle on myönnetty lisäaikaa tentteihin yksilöllisenä järjestelynä.

Ennen kuin ilmoittaudut tenttiin, lue huolellisesti alla olevat ohjeet (i) Jyväskylän yliopiston ohjeet verkkotenttien suorittamiseen ja (ii) kurssin tenttisäännöt ennen tenttiin ilmoittautumista. Jos yliopiston ohjeiden ja opintojakson ohjeiden välillä on ristiriita, opintojakson ohjeet pätevät.

Jyväskylän yliopiston ohjeet verkkotenttien suorittamiseen

Verkkotentin suorittaminen

  • Verkkotenttiin ilmoittaudutaan tentin järjestäjän ohjeiden mukaisesti.
  • Verkkotentti on yksilökoe, ellei tentin järjestäjä ole muuta ohjeistanut. Se suoritetaan ilman ulkopuolisten henkilöiden suoraa tai välillistä apua.
  • Järjestelmään, jossa verkkotentti järjestetään, kirjaudutaan Jyväskylän yliopiston käyttäjätunnuksella ja salasanalla. Käyttäjätunnus on henkilökohtainen, eikä omaa tunnusta saa luovuttaa eteenpäin muille henkilöille.
  • Verkkotentti suoritetaan sille varattuna aikana.
  • Verkkotentin saa suorittaa tietokoneella, tabletilla tai puhelimella. Tentti suositellaan suoritettavaksi tietokoneella.
  • Verkkotentin suorittamisen aikainen yhteydenpito ja viestintä ulkopuolisten henkilöiden kanssa on kielletty.
  • Tentin järjestäjä antaa ennen tenttiä tarkentavat ohjeet mahdollisista aineistoista, materiaaleista ja välineistä, joita tentin suorittamiseen saa käyttää. (Katso seuraavassa alaluvussa olevat kurssin tenttisäännöt.)
  • Verkkotentin suorittamisen aikana saa tarvittaessa käyttää Jyväskylän yliopiston VPN-yhteyttä, mutta ei muita VPN-yhteyksiä.
  • Jos yhteytesi verkkotenttijärjestelmään katkeaa tentin suorittamisen aikana, ilmoita siitä tentin jälkeen tentin järjestäjälle.

Verkkotentin valvonta ja henkilötietojen käsittely

  • Yliopisto valvoo verkkotenttien suorittamista käytettävissä olevin keinoin. Yliopisto voi käyttää valvonnassa ensisijaisesti tietojärjestelmien keräämiä lokitietoja tai live-kuvaa ja toissijaisesti video- ja äänitallenteita.
  • Yliopisto voi tarkistaa opiskelijan henkilöllisyyden tentin aikana.
  • Arkaluonteisia henkilötietoja ei käsitellä verkkotenttien valvonnan yhteydessä.
  • Henkilötietojen käsittelyssä noudatetaan yliopiston tietosuoja- ja tietoturvaohjeita.

Verkkotenttiohjeiden noudattaminen ja vilppi verkkotentissä

  • Opiskelijalla on ehdoton velvollisuus perehtyä ennen tenttiä annettuihin ohjeisiin ja noudattaa niitä yksityiskohtaisesti.
  • Tenttiin osallistuva opiskelija tiedostaa, että Jyväskylän yliopisto valvoo verkkotentin suorittamista ja verkkotenttiohjeiden noudattamista käytettävissä olevin keinoin.
  • Tenttivastaukset voidaan opiskelijan suostumuksella käsitellä plagiaatintunnistusohjelmalla.
  • Vilppi ja vilpin yritys tentissä on kielletty. Vilppiepäilytapauksissa noudatetaan rehtorin päätöstä opiskelun eettisistä ohjeista ja vilppitapausten käsittelystä Jyväskylän yliopistossa. Vilppi johtaa aina opintosuorituksen hylkäämiseen ja voi johtaa kirjalliseen huomautukseen, kirjalliseen varoitukseen tai määräaikaiseen erottamiseen.

Tarkentavat ohjeet opintojakson Ohjelmointi 1 (ITKP102) -tenttiin

Lisäohjeet salitenttiin

  • Tentti suoritetaan paikan päällä valvotussa luentosalissa Jyväskylän yliopiston Agora-rakennuksessa.
  • Tentti suoritetaan ensisijaisesti omalla henkilökohtaisella laitteella. Ilmoita ilmoittautumisen yhteydessä, mikäli sinulla ei ole omaa tietokonetta, niin järjestämme sinulle lainakoneen tenttipäiväksi.
  • Tentti alkaa salissa, kun valvoja antaa luvan aloittaa tentin.
  • Tenttisuorituksen päätteeksi opiskelijan on todistettava henkilöllisyytensä ennen salista poistumista.

Lisäohjeet etätenttiin

  • Tentti suoritetaan etävalvotusti Zoom-ohjelman välityksellä.
  • Tentin aikana opiskelijan tulee jakaa kaikkien näyttöjen ruutukuvat sekä videokuvan itsestään. Tarvittavan laitteiston hankinta on opiskelijan vastuulla. Videokamerana on sallittua käyttää oman puhelimen kameraa.
  • Tentti alkaa, kun valvoja antaa luvan aloittaa tentin.
  • Valvojalla on oikeus pyytää näyttämään videokuvaa ympäristöstä tai pyytää laittamaan mikrofonin päälle.
  • Valvojalla on oikeus pyytää suorittamaan toimintoja tietokoneella, kuten avaamaan tehtävienhallintaa.
  • Valvojalla on oikeus pyytää opiskelijaa todistamaan henkilöllisyytensä tentin aikana.
  • Zoom-puhelusta saa poistua vain valvojan luvalla.

Tentissä sallitut aineistot ja materiaalit

  • Tenttivastausten antamiseen saa käyttää vain tietokonetta. Mobiililaitteiden käyttö on kielletty.
  • Tentin aikana saa käyttää tekstiin ja videoon perustuvia verkkosivuja, mukaan lukien opintojakson materiaaleja, harjoitustehtäviä, ohje- ja dokumentaatiosivuja.
  • Tentin aikana ainoa sallittu hakukone on DuckDuckGo, jonka tekoälyominaisuudet tulee kytkeä pois päältä.
  • Tentin aikana saa käyttää Rideria, Visual Studiota, tai vastaavaa kehitysympäristöä.
  • Tentin aikana saa käyttää Visual Studio Codea, Sublime Textia, tai vastaavaa tekstieditoria.
  • Tentin aikana saa käyttää itse tehtyjä sähköisiä tai paperille kirjoitettuja muistiinpanoja.

Tentissä kielletyt välineet ja menetelmät

  • ChatGPT:n, Geminin, Copilotin tai vastaavien generatiivisten tekoälyteknologioiden käyttö on kielletty. Kielto koskee myös kehitysympäristöjen tekoälylisäkkeitä/-avustimia jne.
  • Tentin aikana ainoa sallittu hakukone on DuckDuckGo, jonka tekoälyominaisuudet tulee kytkeä pois päältä. Muiden hakukoneiden (kuten Google, Bing tai Yahoo) käyttö on kielletty, koska niiden tekoälyominaisuuksia ei voi tällä hetkellä kytkeä pois päältä.
  • Verkkotentti on yksilökoe. Kommunikointi muiden kanssa verkkotentin suorittamisen aikana on ehdottomasti kielletty.

Henkilötietojen käsittely tentissä

  • TIM-järjestelmän keräämiä toimintalokeja voidaan käyttää vilppiepäilytapausten tutkimiseen. Järjestelmän tiedot kerätään ja käsitellään järjestelmän oman tietosuojaselosteen mukaisesti.
  • Live-kuvaa, video- tai äänitallenteita ei tallenneta.

Muita ohjeita

  • Tallenna vastauksesi ennen palautusajan päättymistä, mielellään muutamia minuutteja ennakkoon. Mikäli et ole tallentanut vastaustasi ennen palautusajan päättymistä, menetät viimeisimmät muutoksesi.
  • Vastausten lukumäärää ei ole tentin aikana rajoitettu. Viimeisin tallennettu vastaus arvioidaan. Voit vielä tarkistaa tentin lopussa olevalla painikkeella, että vastasit kaikkiin kysymyksiin.
  • Tentin arvioinnista, arvosanoista ja hyvityspisteistä on kerrottu tarkemmin kurssin suoritusohjeissa.

Tentin aikana ilmenevät tekniset ongelmat

Teknisissä ongelmissa käytä jotakin seuraavista yhteydenottotavoista:

  • Salissa: Nosta kätesi ylös ja odota, että valvoja tulee luoksesi.
  • Etänä: Jätä avunpyyntö lomakkeella: Avunpyyntö etätentissä (linkki tulee tähän hyvissä ajoin ennen tenttiä)
  • Laita viesti osoitteeseen teacher_email
  • Soita numeroon teacher_phone_number
  • Muista, että ongelman sattuessa ei ole kiirettä tai syytä paniikkiin. Vastuuopettaja voi tarvittaessa myöntää lisäaikaa tenttiin.

Luennot

Java-kielen perusteet

osaamistavoitteet

Hei, Java!

osaamistavoitteet

  • Java-kielen perusteet
  • Tiedät miten Java-ohjelma käännetään ja ajetaan (komentoriviohjelmat javac, java ja jshell, IDE-säädöt)
  • Tiedät mikä on (J)VM ja miten kääntäminen eroaa tulkkauksesta
  • Tunnet Java-kielen vastineita yleisimmille I/O-operaatioille (tekstin tulostus, lukeminen konsolilta)

Koodiesimerkki

void main() {
    var feature =  Runtime.version().feature();
    IO.println("Hei, maailma! Tässä on Java " + feature);
}
public class Kissa {
  private String name; 

  // HIGHLIGHT_GREEN_BEGIN
  public Kissa(String name) {
    this.name = name;
  }
// HIGHLIGHT_GREEN_END

// HIGHLIGHT_RED_BEGIN
  public String getAani() { 
// HIGHLIGHT_RED_END
// HIGHLIGHT_YELLOW_BEGIN
    return "Miau!";
// HIGHLIGHT_YELLOW_END
  } 
}
void main() {
   IO.println("summa(2, 2) => " + summa(2, 2));
}

/**
 * Laskee kahden kokonaisluvun summan.
 * 
 * @param a Ensimmäinen luku
 * @param b Toinen luku
 * @return Lukujen summa
 */
int summa(int a , int b) {
    return a + b;
}

Monen tiedoston koodialueet

Ensimmäinen alue

Henkilo.java
public class Henkilo {
    private String name;

    public Henkilo() {
        name = "Denis";
    }

    public String getTervehdys() {
        return "Moi, " + name + "!";
    }
}

Tällä hetkellä main.java:n pitää sisältää pääohjelman johtuen palvelinpuolen ajoympäristön takia. Tosin tuo voitaisiin muokata niin, että pääohjelman tiedostonimi pääteltäisiin automaattisesti.

Toinen koodialue testiksi, että kummatkin alueet ovat erillisiä toisistaan:

main.java
public class Ohjelma {
    public static void main() {
        Kissa k = new Kissa("Snowball");
        IO.println(k.getAani());
    }
}

Muokattavat koodilohkot

Harjoittele tekemällä ja tulostamalla erityyppisiä muuttujia (tämä on editoitava koodausalue):

void main() {
    int luku = 1;
    double liukuluku = 1.0;

    IO.println("luku = " + luku);
    IO.println("liukuluku = " + liukuluku);
}

Taulukko

AvainsanaSelitys
publicnäkyvyysmodifikaattori — julkinen
staticstaattinen wew kuuluu luokalle
voidei palauta arvoa

Huomautus

note

Huomautus!

Toinen

huomautus

Huom!

vinkki

Tässä voit tehdä myös näin:

void main() {
   IO.readln("Lue rivi >");
}

esimerkki

Tämä on esimerkkilohko

varoitus

Tämä on esimerkkilohko

varo

Tämä on esimerkkilohko

Mermaid-tuki

---
config:
  flowchart:
    curve: linear
---
flowchart TD
    Aloitus --> EHTO{EHTO?}
    EHTO -->|tosi| LAUSE
    EHTO -->|epätosi| MUU[Muu koodi]
    LAUSE --> MUU

Testi!

Matikkaa:

Lisää matikkaa:

Tehtävä: Tulosta luvut 1-10 1 p.

Kirjoita ohjelma, joka tulostaa lukuja 1-10, kukin omalle riville.

Esimerkki:

1
2
3
4
5
6
7
8
9
10
Tee tehtävä TIMissa

Muuttujat ja tietotyypit

osaamistavoitteet

  • Kerrataan lyhyesti rakenteisen ohjelmoinnin perusteet
  • Muuttujat ja vakiot (perustyypit, final, String)

Tämä on kissa

Tervetuloa kissojen maailmaan! Tässä osiossa opit kaiken kissoista ja niiden hoidosta.

Ohjausrakenteet

osaamistavoitteet

  • Kerrataan lyhyesti rakenteisen ohjelmoinnin perusteet
  • Ehtolauseet (if, switch)
  • Toistolauseet (for, while, do-while), ja listatyyppiset tietorakenteet
  • Tiedostat, että Javassa merkkijonot verrataan equals-aliohjelmalla eikä ==

Aliohjelmat

osaamistavoitteet

  • Käsitellään dataa funktioiden avulla (Ohj1-kurssin tapaan)
  • Funktiot (määrittely, kirjoitusasu, palautusarvot, ehkä hieman datan käsittelyä kertauksena)
  • Ymmärrät Javan perustietotyyppien ja viitetyyppien eron funktion kutsussa (oliot ovat aina viitteen takana)
  • Dokumentaatiokommentit
  • Osaat kirjoittaa Ohjelmointi 1 -kurssin tapaisia ohjelmia Javalla

Osan kaikki tehtävät

Olio-ohjelmoinnin perusteet

osaamistavoitteet

Kohti olio-ohjelmointia

osaamistavoitteet

  • Eteneminen "data+funktio"-ajatuksesta (Ohj1) kohti "tila+metodi"-ajatusta (Ohj2)
  • Proseduraalisesta ohjelmoinnista ("data+funktio") olio-ohjelmointiin ("tila+metodi+viestit")
  • Ymmärrät luokkien ja olioiden roolin olio-ohjelmoinnissa (Tieto ja toiminnallisuus yhdessä paketissa)

Luokka ja olio

osaamistavoitteet

  • Luokka ja olio
  • Konstruktori, metodi, attribuutti
  • Luokan rakenne ja suhde olioon (konstruktori, attribuutti, metodi, this-viite, "luokka blueprintina oliolle")
  • final attribuuttien kanssa
  • Osaat määritellä ja hyödyntää omia luokkia Javalla

Kapselointi

osaamistavoitteet

  • Ymmärrät kapseloinnin ja sen hyödyt (Decoupling/Coupling)
  • Toteutetaan olioiden yhteistyö pienessä olioverkossa. Pidetään kytkentä löyhänä, eli olioiden välinen riippuvuus on vain rajapinnan (metodien) varassa, ei sisäisen toteutuksen varassa.
  • julkisuusmääreet public ja private, getterit ja setterit, metodi pääasiallisena tapana olioille "viestiä"
  • Kutsuja ei tiedä (eikä voi riippua siitä) miten olion tila on toteutettu. Toteutustaa voi muuttaa ilman että kutsujan tarvitsee muuttaa koodiaan.

Osan kaikki tehtävät

Perintä ja rajapinnat

osaamistavoitteet

  • Osaat tehdä luokkahierarkian käyttämällä perintää
  • Osaat korvata kantaluokan toiminnallisuuden
  • Ymmärrät konkreettisten ja abstraktien luokkien eron
  • Osaat käyttää rajapintoja määrittääksesi luokan toimintaa määrittävän sopimuksen
  • Ymmärrät, miten polymorfismi mahdollistaa erilaisten luokkien käsittelyn yhtenäisesti

huomautus

Tämän osan tehtävien palautuksen takaraja on 31.1.2026 klo 23:59.

Perintä

osaamistavoitteet

  • Perintä: "Opiskelija on Henkilo", metodin korvaaminen, protected, luokkahierarkia
  • Käytetään perintää olioiden yhteistyössä
  • Ymmärrät miten luokat ja oliot voivat periä toistensa ominaisuuksia
  • Ymmärrät miten metodeja voi korvata luokan sisällä ja luokkien yli
  • Korvaaminen, @Override, final
  • Osaat luoda yksinkertaisen luokkahierarkian, jossa luokka perii toisen luokan ja korvaa sen metodeja
  • Object-luokka ja sen korvattavat metodit
  • Ymmärtää, että kaikki Javan luokat perivät Object-luokasta
  • Tuntee hyödylliset korvattavat metodit Object-luokassa: equals, toString, (ehkä hashCode?)

Perintä tarkoittaa mekanismia, jossa luokka sisällyttää itseensä toisen luokan ominaisuudet (attribuutit) ja toiminnallisuudet (metodit). Tämä mahdollistaa koodin uudelleenkäytön ja luokkien välisen hierarkian luomisen.

Esimerkki

Käytännössä olioilla on usein yhteisiä piirteitä. Otetaan keksitty esimerkki henkilötietojärjestelmästä: Maija Opiskelija, Olli Opettaja ja Satu Sihteeri voisivat kaikki olla olioita kuvitteellisessa Kisu-opintotietojärjestelmässä. Kaikilla näillä on kaikille käyttäjille tyypillisiä ominaisuuksia, kuten nimi ja käyttäjätunnus. Jokaisen pitäisi myös päästä kirjautumaan sisään järjestelmään ja sieltä ulos.

Kullakin käyttäjällä on kuitenkin myös omia erityispiirteitään: Opiskelijalla voisi olla lista kursseista, joille hän on ilmoittautunut, sekä hänen suorittamansa opintopisteet. Opettajalla on kurssit, joita hän opettaa sekä tehtävänimike, mutta hänellä ei ole opintopisteitä. Sihteeri on vastuussa opintosuoritusten kirjaamisesta ja tutkinnon antamisesta, mutta hänellä ei ole opiskelijanumeroa tai opetettavia kursseja.

Lähdetään kuitenkin aluksi liikkeelle pienesti. Alla on Opiskelija- ja Opettaja-luokat, joihin olemme tehneet pari attribuuttia ja metodia. Tutki näitä luokkia.

varoitus

Alla oleva esimerkki on tarkoitettu havainnollistamaan perinnän syntaksia, eikä siitä syystä noudata (vielä) parhaita käytäntöjä. Erityisesti nimen asettaminen julkisella setNimi-metodilla rikkoo tiedon piilottamisen periaatetta (ks. Luku 2.1). Korjaamme tämän asian kuitenkin esimerkin edetessä.

Opiskelija.java
import java.util.ArrayList;

class Opiskelija {
    String nimi;
    ArrayList<String> kaynnissaOlevatKurssit;

    public Opiskelija() {
        this.kaynnissaOlevatKurssit = new ArrayList<>();
    }

    String getNimi() {
        return this.nimi;
    }

    void setNimi(String nimi) {
        this.nimi = nimi;
    }

    void naytaOpintosuunnitelma() {
        String kurssit = String.join(", ", kaynnissaOlevatKurssit);
        IO.println(this.nimi + " opiskelee kursseilla: " + kurssit);
    }

    void ilmoittauduKurssille(String kurssi) {
        IO.println(this.nimi + " ilmoittautui kurssille: " + kurssi);
        kaynnissaOlevatKurssit.add(kurssi);
    }

}

Huomaat, että kummassakin luokassa on samat attribuutti nimi sekä metodit getNimi ja setNimi. Näiden luokkien välillä on toki myös eroja, mutta nimen omaan toisto on ongelmallista, koska:

  • jokaisessa luokassa on määriteltävä samat ominaisuudet ja toiminnot uudelleen,
  • jos haluamme muuttaa jotain yhteistä ominaisuutta tai toimintoa, meidän täytyy tehdä se kolmessa eri paikassa,
  • uuden luokan lisääminen, jolla on samat ominaisuudet, vaatii saman koodin kopioimisen uudelleen taas uuteen paikkaan.

Jos nyt haluaisimme muuttaa esimerkiksi nimi-attribuuttia niin, että etunimi ja sukunimi tallennetaan erikseen kahteen attribuuttiin, meidän pitäisi tehdä tämä muutos kaikissa näissä luokissa. Tämä lisää virheiden mahdollisuutta ja tekee koodin ylläpidosta hyvin hankalaa. Yksi ohjelmistokehityksen periaatteista onkin älä toista itseäsi (Don't Repeat Yourself, lyh. DRY; ks. Wikipedia).

Luokkahierarkia

Toistamisen välttämiseksi voimme luoda yliluokan (engl. superclass) nimeltä Henkilo, joka sisältää kaikki yhteiset ominaisuudet ja toiminnot. Sitten alaluokat (engl. subclass) Opiskelija ja Opettaja voivat periä Henkilo-luokan, jolloin ne saavat automaattisesti kaikki sen määrittelemät ominaisuudet ja metodit. Näin voimme lisätä vain erityispiirteet kuhunkin aliluokkaan ilman koodin toistamista.

Toteutetaan nyt yllä kuvattu tilanne uudestaan niin, että kirjoitetaan kaikissa luokissa esiintyvät ominaisuudet ja toiminnot uuteen Henkilo-luokkaan, ja Opiskelija ja Opettaja perivät kyseisen luokan. Javassa perintä toteutetaan käyttämällä extends-avainsanaa. Esimerkiksi class Opiskelija extends Henkilo tarkoittaa, että Opiskelija-luokka perii Henkilo-luokan. Tehdään tämä muutos koodissamme.

Henkilo.java
public class Henkilo {
    String nimi;

    String getNimi()
    {
        return this.nimi;
    }

    void setNimi(String nimi) {
        this.nimi = nimi;
    }
}

Huomaa, että Opiskelija- ja Opettaja-luokat eivät enää määrittele nimi--attribuuttia tai getNimi- ja setNimi-metodeja, koska ne perivät nämä Henkilo-luokasta, eikä sitä koodia enää tarvitse uudelleen kirjoittaa. Tämä tekee koodista huomattavasti siistimpää ja helpommin ylläpidettävää. Perinnällä siis määritetään yksi yliluokka (tässä Henkilo) ja aliluokka tai aliluokat (tässä Opiskelija ja Opettaja), jotka laajentavat (engl. extend) Henkilo-luokan lisätiedoilla ja -toiminnallisuuksilla opiskelijasta ja opettajasta.

Toisin sanoen, Opiskelija ja Opettaja saavat itselleen samat (ei-yksityiset) attribuutit ja (ei-yksityiset) metodit kuin Henkilo-luokka ilman sitä, että ne pitää erikseen määritellä aliluokissa.

Periytymistä voidaan kuvata alla olevan tapaisella kuviolla. Tässä Henkilo on yliluokka (superclass) ja Opiskelija ja Opettaja ovat aliluokkia (subclasses), jotka perivät Henkilo-luokan ominaisuudet ja metodit.

classDiagram
    Henkilo <|-- Opiskelija
    Henkilo <|-- Opettaja

Yllä oleva kuvio on tehty mukaillen niin sanottua UML-kuvauskieltä (engl. Unified Modelling Language). Tarkkaan ottaen UML:ssä kunkin luokan kohdalle lisätään myös muutakin tietoa, kuten attribuuttien ja metodien nimet ja tieto kunkin näiden näkyvyydestä. Jätämme ne kuitenkin tässä esimerkissä yksinkertaisuuden vuoksi pois ja käytämme UML:ää tässä sopivasti soveltaen; palaamme UML:ään tarkemmin myöhemmissä osissa.

Rakentajat ja super-avainsana

Yllä olevassa esimerkissämme on pari ongelmaa. Ensinnäkin, Henkilo-luokassa ei ole rakentajaa, nimen alustaminen tapahtuu setNimi-metodin kautta. Tämän seurauksena olioiden luomisen jälkeen nimi-attribuutti on aina null, ennen kuin se asetetaan erikseen. Tämä ei ole hyvä käytäntö kahdestakin syystä: Ensinnäkin, on parempi, että olio on käyttökelpoinen heti luomisen jälkeen ilman, että erillisiä asettamisia tarvitsee tehdä. Toiseksi, nimen asettaminen julkisen setNimi-metodin kautta ei ole hyvä idea, sillä se rikkoo tiedon kapseloinnin periaatetta.

Vaikka nimen muuttaminen toki pitäisikin tietyissä tilanteissa olla opintotietojärjestelmässä mahdollista, sen asettaminen julkisen metodin kautta, eli niin, että mikä tahansa olio voisi kutsua minkä tahansa Henkilo-olion metodia nimen muuttamiseksi, ei pitäisi olla sallittua, vaan pitäisi tapahtua huomattavasti hallitumman prosessin kautta.

Asetetaan aluksi nimi-attribuutti yksityiseksi Henkilo-luokassa. Lisätään sitten rakentaja, joka ottaa nimi-parametrin, ja alustaa attribuutin arvon vastaavasti. Tämän jälkeen voimme poistaa setNimi-metodin kokonaan, jolloin nimen asettaminen onnistuu vain rakentajan kautta. Niinpä nimen muuttaminen ei enää onnistu, mutta tämä sopii meille tässä vaiheessa.

Muutetaan olioiden rakentaminen pääohjelmassa vastaamaan tätä uutta rakentajaa.

Henkilo.java
class Henkilo {

    // HIGHLIGHT_GREEN_BEGIN
    private String nimi;

    public Henkilo(String nimi) {
        this.nimi = nimi;
    }
    // HIGHLIGHT_GREEN_END

    // HIGHLIGHT_RED_BEGIN
    void setNimi(String nimi) {
        this.nimi = nimi;
    }
    // HIGHLIGHT_RED_END

    public String getNimi() {
        return this.nimi;
    }
}

Nyt koska Henkilo-luokassa on määritelty rakentaja, joka ottaa parametreja, Java ei enää luo oletusrakentajaa (siis sellaista, jossa ei ole parametreja) automaattisesti, mikä aiheuttaa käännösvirheen.

Tässä tuleekin tärkeä huomio: Ne luokat, jotka perivät Henkilo-luokan, eivät peri sen rakentajaa. Tämän vuoksi meidän on lisättävä myös Opiskelija ja Opettaja-luokkiin rakentajat vastaamaan tätä muutosta.

Toisaalta nyt kun määrittelimme nimi-attribuutin yksityiseksi, emme voi myöskään asettaa niitä perivästä luokasta käsin, esimerkiksi seuraavasti.

class Opiskelija extends Henkilo {
    public Opiskelija(String nimi) {
        // HIGHLIGHT_YELLOW_BEGIN
        this.nimi = nimi;
        // HIGHLIGHT_YELLOW_END
    }
}
Opiskelija.java:6:5
java: constructor Henkilo in class Henkilo cannot be applied to given types;
  required: java.lang.String
  found:    no arguments
  reason: actual and formal argument lists differ in length

Opiskelija.java:8:13
java: nimi has private access in Henkilo

Ensimmäinen virhe liittyy siihen, että Henkilo-luokassa ei ole oletusrakentajaa. Palaamme tähän asiaan hieman myöhemmin. Jälkimmäinen virhe on tämän hetkinen ongelmamme: nimi-attribuutti on yksityinen, joten emme voi asettaa sitä suoraan perivästä luokasta käsin.

Ainoa tapa tallentaa ja lukea arvot näihin attribuutteihin on tehdä se kutsumalla aliluokasta yliluokan rakentajaa ja välittämällä tuossa kutsussa tarvittavat parametrit. Tämä kutsuminen toteutetaan käyttämällä super-avainsanaa. Tehdään tämä muutos kumpaankin aliluokkaan. Muutetaan samalla myös loputkin attribuutit yksityisiksi.

import java.util.ArrayList;
class Opiskelija extends Henkilo {
    // HIGHLIGHT_GREEN_BEGIN
    private ArrayList<String> kaynnissaOlevatKurssit;
    // HIGHLIGHT_GREEN_END

    // HIGHLIGHT_GREEN_BEGIN
    public Opiskelija(String nimi) {
        super(nimi);
        kaynnissaOlevatKurssit = new ArrayList<>();
    }
    // HIGHLIGHT_GREEN_END
    // ...
}

Tee vastaava muutos myös Opettaja-luokkaan.

Tämän jälkeen ohjelma ei kuitenkaan vielä käänny, koska perivissä luokissa emme edelleenkään pääse käsiksi yliluokan yksityiseen nimi-attribuuttiin.

class Opiskelija extends Henkilo {
    void naytaOpintosuunnitelma() {
        String kurssit = String.join(", ", kaynnissaOlevatKurssit);
        // HIGHLIGHT_YELLOW_BEGIN
        IO.println(this.nimi + " opiskelee kursseilla: " + kurssit);
        // HIGHLIGHT_YELLOW_END
        // Käännösvirhe: nimi on yksityinen muuttuja
    }
}

Ainoa tapa päästä käsiksi nimi-attribuuttiin on kutsua yliluokan getNimi()-metodia, sillä se on julkinen. Tehdään tämä muutos kaikkiin kohtiin, joissa nimi-attribuuttiin viitataan suoraan perivissä luokissa.

Henkilo.java
class Henkilo {
    private String nimi;

    public Henkilo(String nimi)
    {
        this.nimi = nimi;
    }

    public String getNimi()
    {
        return nimi;
    }
}

Oletusrakentajaa emme tarvitse enää, joten jätämme sen toteuttamatta.

Esimerkkiä voitaisiin jatkaa vielä pidemmälle. Meillä voisi olla myös Sihteeri, joka voi kirjata opintosuorituksia. Sihteeri peritään Henkilo-luokasta. Voisimme tehdä myös kahdenlaisia erilaisia opiskelijoita: Tutkinto-opiskelijoita sekä Avoimen yliopiston opiskelijoita. Tutkinto-opiskelijalla on oma tutkinto-ohjelma, kun taas Avoimen opiskelijalla ei ole tutkinto-ohjelmaa. Toisaalta Avoimen opiskelijan täytyy suorittaa maksu ennen kuin hän voi saada opintopisteitä.

Luokkahierarkia näyttäisi nyt seuraavalta:

classDiagram
    class Henkilo
    Henkilo <|-- Opiskelija
    Henkilo <|-- Opettaja
    Henkilo <|-- Sihteeri
    Opiskelija <|-- TutkintoOpiskelija
    Opiskelija <|-- AvoinOpiskelija

Jätämme esimerkin tässä toteuttamatta, mutta voit halutessasi tutkia valmista koodia täällä.

Huomautetaan vielä, että super-avainsanalla kutsutaan nimen omaan luokan välitöntä yliluokkaa. Luokkarakenteessa "yli hyppiminen" ei ole mahdollista. Esimerkiksi TutkintoOpiskelija-luokan rakentaja voisi kutsua vain Opiskelija-luokan rakentajaa, ei Henkilo-luokan rakentajaa.

is-a-suhde

Perintäsuhteesta käytetään englanninkielistä termiä is-a-suhde. Voimmekin sanoa, että Opiskelija on Henkilo, Opettaja on Henkilo ja Sihteeri on Henkilo -- nimen omaan näin päin. Edelleen, myös TutkintoOpiskelija on Henkilo, koska se perii Opiskelija-luokan, joka puolestaan perii Henkilo-luokan.

Tämän ansiosta voimme käsitellä Opiskelija, Opettaja ja Sihteeri-olioita koodissamme Henkilo-luokan olioina, kun ei ole tarpeen tietää tarkasti, minkä aliluokan olioita käsittelemme. Tämä on hyödyllistä esimerkiksi silloin, kun haluamme käsitellä henkilöitä yhtenä ryhmänä.

Lisätään kaikki tekemämme oliot Henkilo-taulukkoon:

Opiskelija opiskelija = new Opiskelija();
Opettaja opettaja = new Opettaja();
Sihteeri sihteeri = new Sihteeri();

Henkilo[] henkilot = {opiskelija, opettaja, sihteeri};

Jotta esimerkkimme olisi vähän mielekkäämpi, lisätään vielä Henkilo-luokkaan metodit kirjaudu() ja kirjauduUlos(). Nyt siis kaikki henkilöt perivät nämä metodit.

class Henkilo {
    // HIGHLIGHT_GREEN_BEGIN
    private boolean kirjautunut;
    // HIGHLIGHT_GREEN_END

    public Henkilo(String nimi) {
        // ...
        // HIGHLIGHT_GREEN_BEGIN
        this.kirjautunut = false;
        // HIGHLIGHT_GREEN_END
        // ..
    }

    // HIGHLIGHT_GREEN_BEGIN
    void kirjaudu() {
        this.kirjautunut = true;
        IO.println(this.getNimi() + " kirjautui sisään.");
    }
    void kirjauduUlos() {
        this.kirjautunut = false;
        IO.println(this.getNimi() + " kirjautui ulos.");
    }
    // HIGHLIGHT_GREEN_END
}

Voimme nyt kutsua vaikkapa kirjauduUlos()-metodia kaikille henkilot-taulukon olioille ilman, että meidän tarvitsee tietää tarkasti, minkä tyyppisiä olioita taulukossa on:

for (Henkilo henkilo : henkilot) {
    henkilo.kirjauduUlos();
}

Huomionarvoista on is-a-suhteen suunta; Opettaja ei ole Sihteeri, vaikkakin molemmat perivät Henkilo-luokan.

Huomautus moniperinnän puuttumisesta

Javassa luokka voi periä vain yhden luokan. Joissain muissa ohjelmointikielissä, kuten C++:ssa, on mahdollista käyttää moniperintää (engl. multiple inheritance), jossa luokka voi periä useamman kuin yhden luokan. Emme tässä mene syvemmälle moniperinnän käsitteeseen, mutta mainittakoon, moniperinnän käyttö voi joissain tilanteissa olla ongelmallista (esim. Timanttiongelma).

Usein kirjallisuudessa mainitaan, että Javassa moniperintää muistuttaa hieman rajapinnan käsite (engl. interface). Kysymys on kuitenkin monin tavoin eri asiasta. Rajapintoja käsitellään osassa 3.2 Rajapinnat ja abstraktit luokat.

Korvaaminen

Perityn luokan metodeja voidaan korvata (engl. override) aliluokassa, mikä tarkoittaa, että aliluokka voi määritellä oman version peritystä metodista. Tämä on hyödyllistä, kun haluamme muuttaa perityn metodin käyttäytymistä aliluokassa.

Lisätään yllä olevaan Opiskelija-esimerkkimme attribuutti boolean opintoOikeusVoimassa, joka ilmaisee, onko opiskelijalla voimassa oleva opinto-oikeus. Jos opinto-oikeus ei ole voimassa, opiskelija ei voi kirjautua järjestelmään. Korvataan kirjaudu()-metodi Opiskelija-luokassa tarkistamaan tämä ehto ennen kirjautumista.

class Opiskelija extends Henkilo {

    // ...

    boolean opintoOikeusVoimassa;

    @Override
    void kirjaudu() {
        if (opintoOikeusVoimassa) {
            super.kirjaudu(); // Kutsutaan yliluokan kirjaudu-metodia
        } else {
            System.out.println("Opinto-oikeus ei ole voimassa. Et voi kirjautua.");
        }
    }
}

Muissa Henkilo-luokan aliluokissa, kuten Opettaja ja Sihteeri, kirjaudu()-metodi toimii edelleen alkuperäisellä tavalla, koska niitä ei ole korvattu.

Voidaan ajatella, että korvattu metodi korvaa yliluokan metodin aliluokassa. Tähän liittyy pari sääntöä:

  • Korvaaminen koskee aina hierarkiassa lähintä yliluokan metodia.
  • Kun aliluokan olion metodia kutsutaan, kutsu viittaa aina hierarkiassa lähimpään korvattuun versioon.

Alla oleva koodi havainnollistaa korvaamista ja kutsujen välittymistä luokkahierarkiassa.

A.java
class A {  
    public void hei() { IO.println("A-olio sanoo hei."); }  
    public void moikka() { IO.println("A-olio sanoo moikka."); }  
    public void huhhuh() { IO.println("A-olio sanoo huh huh!!."); }  
}  

Object-luokka

Javassa kaikilla luokilla on yhteinen yliluokka nimeltä Object. Tämä tarkoittaa, että kaikki luokat perivät automaattisesti Object-luokan ominaisuudet ja metodit, ellei toisin määritellä. Object-luokassa on useita hyödyllisiä metodeja, joita voidaan korvata aliluokissa.

Yksi tyypillinen tapa käyttää korvata Object-luokan toString()-metodia, joka tarjoaa olion merkkijonoesityksen. Oletusarvoisesti toString() palauttaa olion luokan nimen ja sen hajautusarvon, mikä ei välttämättä ole kovin informatiivista. Voimme korvata tämän metodin omassa luokassamme, jotta se palauttaa juuri meidän tarpeisiimme sopivan merkkijonoesityksen. Lisätään toString()-metodi Henkilo-luokkaan.

class Henkilo {

    // ...

    @Override
    public String toString() {
        return "Henkilö: " + this.getNimi()";
    }
}

Perimisen tai korvaamisen estäminen (final-avainsana)

Luokan periminen tai metodin korvaaminen voidaan estää käyttämällä final-avainsanaa. Kun luokka on merkitty final-avainsanalla, sitä ei voi periä. Vastaavasti, kun metodi on merkitty final-avainsanalla, sitä ei voi korvata aliluokassa.

Ehkä hieman hämäävästi final-avainsanaa voidaan käyttää myös muuttujien yhteydessä, jolloin se tarkoittaa, että muuttujan arvoa ei voi muuttaa sen alustamisen jälkeen. Tällä ei ole kuitenkaan tekemistä perinnän kanssa.

Tehtävät

Tehtävä 3.1: Luokkahierarkia, osa 1. 1 p.

Tee luokkahierarkia ajoneuvoille. Yliluokasta Ajoneuvo periytyvät aliluokat Auto, Moottoripyora ja Polkupyora.

Määrittele yhteiset ominaisuudet (nopeus, paino) ja metodit (kiihdyta(), jarruta()) Ajoneuvo-luokassa.

Kiihdyttäminen kasvattaa ajoneuvon nopeutta ja jarruttaminen vähentää sitä.

Lisää erityispiirteitä kuhunkin aliluokkaan:

  • Auto: ovienLukumaara
  • Moottoripyora: sivuvaunu
  • Polkupyora: vaihteidenLukumaara

Testaa luokkia luomalla olioita ja kutsumalla metodeja. Dokumentoi luokat ja metodit huolellisesti.

Tee tehtävä TIMissä

.

Tehtävä 3.2: Luokkahierarkia, osa 2. 1 p.

Laajenna edellistä ajoneuvojen luokkahierarkiaa lisäämällä uusi aliluokka Sahkoauto, joka perii Auto-luokasta. Lisää Sahkoauto-luokkaan ominaisuus akunKapasiteetti ja metodi lataaAkku(), joka simuloi akun lataamista. Jos akku on täynnä, ei ladata enää lisää.

Testaa kumpaakin auto-luokkaa luomalla niistä olio ja kutsumalla metodeja.

Tee tehtävä TIMissä

.

✨ Bonus: Tehtävä 3.3: Luokkahierarkia, osa 3. 1 p.

Lisää Auto-luokalle vakio TOIMINTASADE_MAX, joka ilmaisee maksimietäisyyden kilometreinä, jonka auto voi kulkea yhdellä latauksella tai tankkauksella. Lisää Auto-luokkaan metodi tankkaaKayttovoimaa(), joka lisää ajoneuvolle käyttövoimaa (bensiiniä tai sähköä).

Lisää sitten Sahkoauto-luokkaan attribuutti akunKunto (prosentteina; väliltä 0-100) sekä toimintasade (kilometreinä). Kun autoa ladataan, akun kunto heikkenee (ja siten toimintasäde) 0.1%:lla jokaisella latauskerralla. Niinpä toimintasade tulee laskea akun kunnon perusteella akunKunto / 100 * TOIMINTASADE_MAX.

Tee tehtävä TIMissä

Abstraktit luokat

osaamistavoitteet

  • Abstrakti luokka tarjoaa osan toteutuksesta ja määrittelee "rajapinnan" sille, mitä perittävän luokan tulee toteuttaa itse.
  • Abstraktit luokat (abstrakti metodi)
  • Ymmärrät, että abstraktista luokasta ei voi luoda luokan ilmentymiä

Polymorfismi

osaamistavoitteet

  • Polymorfismi (dynaaminen sidonta, rajapinnat ja abstraktit luokat voivat olla muuttujan tai parametrin tyyppeinä)
  • Tunnistaa polymorfismin merkitys olioiden yhteistyössä. Olio, joka käyttää ylätason tyyppiä (rajapinta, abstrakti luokka) voi toimia erilaisten aliluokkien kanssa.
  • Kutsuttava metodi päätetään ajon aikana olion todellisen tyypin perusteella, ei muuttujan tyypin perusteella.
  • Osaat hyödyntää rajapintoja ja abstrakteja luokkia luokkienvälisen riippuvuuden välttämiseksi

Huomautus instanceof-operaattorista

Javassa on mahdollista tarkistaa, onko olio tietyn luokan ilmentymä käyttämällä instanceof-operaattoria. Esimerkiksi:

On kuitenkin niin, että instanceof-operaattorin käyttö tarkoittaa varsin usein sitä, ettei perintää ja polymorfismia ole hyödynnetty optimaalisella tavalla, jonka seurauksena koodiin tulee runsaasti ehtolauseita, jotka tarkistavat olion tyypin ja suorittavat sen perusteella erilaisia toimintoja. Tällöin menetetään olio-ohjelmoinnin keskeinen etu, eli se, että olioiden erilaiset toteutukset voidaan piilottaa niiden käyttäjiltä. Käytännössä ainoa, missä kyseistä operaattoria tarvitsee, on, jos käsitellään Object-olioita jonkin hyvin matalan tason yleisluokan kautta.

Rajapinnat

osaamistavoitteet

  • Ymmärtää rajapinnan (interface) rooli ja käyttää sitä vaihtokohdissa (strategiat, palvelut).
  • Rajapinnat ("Kissa osaa Puhua, Kävellä, Hyppiä...")
  • abstrakti luokka vs. rajapinta (rajapintametodin oletustoteutus)
  • Ymmärrät, että luokka voi toteuttaa monta rajapintaa, mutta periä vain yhdestä luokasta
  • Testaaminen rajapintaa vasten, ei toteutusta vasten.
  • "Moniperintä" rajapintojen avulla
  • Käytetään perintää ja rajapintoja olioiden yhteistyössä

Osan kaikki tehtävät

Hyödyllisiä menetelmiä olio-ohjelmoinnissa

osaamistavoitteet

Geneeriset luokat

osaamistavoitteet

  • Templaatit luokille ja metodeille (, "geneerinen tyyppi" käsitteenä)
  • Osaat hyödyntää geneerisiä tyyppejä ja tyyppiparametreja toteuttaaksesi yleiskäyttöisiä luokkia ja metodeja
  • Geneerisyys, tyyppiparametrit

Tyyppitarkistukset ja tyyppimuunnokset

osaamistavoitteet

  • Tyyppitarkistukset ja tyyppimuunnokset (instanceof, casting)
  • switch-lauseke, pattern matching

Muita hyödyllisiä rajapintoja Javassa

osaamistavoitteet

  • Tuntee hyödyllisiä Java-kielen rajapintoja
    • Vertailurajapintoja (Comparable) -> mahdollistaa Javan järjestämismetodien käytön (Arrays.sort jne.)
    • Cloneable -> mahdollistaa olion todellisen kopioinnin (vrt. viite)
    • Iterable<T>-rajapinta ja for-each-silmukka
    • Bonus: Vertailuluokka (Comparator) -> mahdollistaa määrittää useita erilaisia vertailutapoja samalle luokalle

Osan kaikki tehtävät

Tietorakenteita ja algoritmeja

osaamistavoitteet

Kokoelmarajapinnat

osaamistavoitteet

  • List, Set, Map. Oikean kokoelman valinta käyttötarkoituksen mukaan.
  • Tunnet Java-kielen kokoelmarajapinnat ja niitä toteuttavia tietorakenteita: List, Set, Map
  • Collections-luokka ja Collection-rajapinta

Valmiit kokoelmat Javassa

osaamistavoitteet

  • Tunnet Java-kielen yleisimmät valmiit tietorakenteet ArrayList, HashMap, LinkedList, Stack, Queue
  • Rajapintaa vasten ohjelmointi: List, Set, Map
  • Lyhyesti käydään läpi vaikutukset suorituskykyyn: ArrayList, HashMap, List, Set
  • Ymmärrät ym. tietorakenteiden keskeisimmät operaatiot ja niiden aikakompleksisuudet
  • Ymmärrät, miksi hashCode tarvitaan (HashMap tapauksessa ainakin)

Esimerkki: oma ArrayList-toteutus

osaamistavoitteet

TODO: Pitäisikö olla sen sijaan ohjattu tehtävä? TAI: Voisi tehdä Full Stack Moocin tavoin ohjatusti ja sitten tehtävänä on tehdä LinkedList tai HashMap. Vrt. myös HY

Rekursio

osaamistavoitteet

  • Ymmärrät miten rekursio toimii
  • Ymmärrät, miten rekursio voi mallintaa pinon avulla
  • Rekursio, perus- ja induktiotapaukset, rekursiivinen tietorakenne (?). Hajota ja hallitse -periaate. Pinon käyttö rekursiossa.
  • Mahdollisesti jotakin dynaamisesta ohjelmoinnista (?)

Osan kaikki tehtävät

Hyödyllisiä menetelmiä Javassa

osaamistavoitteet

Funktiorajapinnat ja lambda-lausekkeet

osaamistavoitteet

  • Funktionaalinen ohjelmointi
  • Funktionaalinen rajapinta ja Javan Function, BiFunction
  • lambda-lausekkeet

Kokoelmien käsittely: Stream API

osaamistavoitteet

  • Ainakin map, filter, reduce
  • lambda-lausekkeiden käyttö Stream API:ssa
  • Stream, IntStream, ero iteraattoreihin

Poikkeusten hallinta

osaamistavoitteet

  • Poikkeukset (checked, unchecked), try-catch, finally, heittäminen (throw, throws).
  • Optional-luokka: isPresent, ifPresent, orElse, map, flatMap

Ulkoiset kirjastot ja Java-projektien hallintatyökalut

osaamistavoitteet

  • Build-työkalut (Gradle/Maven)
  • Kolmannen osapuolen riippuvuuksia (miten etsitään ja lisätään kirjasto)
  • Pakkaukset Javassa

Tiedostojen käsittely

osaamistavoitteet

  • Osaat käsitellä tiedostoja Javan valmiiden rajapintojen kautta (Tiedostomuotojen käsittely "käsin" (CSV) ja kirjastolla (JSON))
  • Files API
  • Tietovirrat (Stream) ja sen oheisluokat (BufferedReader/Writer, Scanner)
  • Yksinkertaisen tiedoston lukeminen (CSV-tyylinen)
  • Jokin JSON-kirjasto ja JSON-tiedoston lukeminen: Gson, Jackson, org.json???

Osan kaikki tehtävät